1
0
mirror of https://github.com/hrfee/jfa-go.git synced 2024-12-29 12:30:11 +00:00

Compare commits

..

No commits in common. "11eb907cededb96d35606728b3b019362f117e8f" and "bb41bc3844641575600812d986086ca16169bc2f" have entirely different histories.

12 changed files with 112 additions and 98 deletions

View File

@ -110,7 +110,11 @@ func (app *appContext) NewUserFromInvite(gc *gin.Context) {
gc.JSON(200, validation) gc.JSON(200, validation)
return return
} }
completeContactMethods := make([]ContactMethodKey, len(app.contactMethods)) completeContactMethods := make([]struct {
Verified bool
PIN string
User ContactMethodUser
}, len(app.contactMethods))
for i, cm := range app.contactMethods { for i, cm := range app.contactMethods {
completeContactMethods[i].PIN = cm.PIN(req) completeContactMethods[i].PIN = cm.PIN(req)
if completeContactMethods[i].PIN == "" { if completeContactMethods[i].PIN == "" {
@ -164,16 +168,13 @@ func (app *appContext) NewUserFromInvite(gc *gin.Context) {
return return
} }
if app.ConfirmationKeys == nil { if app.ConfirmationKeys == nil {
app.ConfirmationKeys = map[string]map[string]ConfirmationKey{} app.ConfirmationKeys = map[string]map[string]newUserDTO{}
} }
cKeys, ok := app.ConfirmationKeys[req.Code] cKeys, ok := app.ConfirmationKeys[req.Code]
if !ok { if !ok {
cKeys = map[string]ConfirmationKey{} cKeys = map[string]newUserDTO{}
}
cKeys[key] = ConfirmationKey{
newUserDTO: req,
completeContactMethods: completeContactMethods,
} }
cKeys[key] = req
app.confirmationKeysLock.Lock() app.confirmationKeysLock.Lock()
app.ConfirmationKeys[req.Code] = cKeys app.ConfirmationKeys[req.Code] = cKeys
app.confirmationKeysLock.Unlock() app.confirmationKeysLock.Unlock()
@ -186,7 +187,7 @@ func (app *appContext) NewUserFromInvite(gc *gin.Context) {
} else if err := app.email.send(msg, req.Email); err != nil { } else if err := app.email.send(msg, req.Email); err != nil {
app.err.Printf(lm.FailedSendConfirmationEmail, req.Code, req.Email, err) app.err.Printf(lm.FailedSendConfirmationEmail, req.Code, req.Email, err)
} else { } else {
app.debug.Printf(lm.SentConfirmationEmail, req.Code, req.Email) app.err.Printf(lm.SentConfirmationEmail, req.Code, req.Email)
} }
return return
} }
@ -222,32 +223,10 @@ func (app *appContext) NewUserFromInvite(gc *gin.Context) {
} }
app.checkInvite(req.Code, true, req.Username) app.checkInvite(req.Code, true, req.Username)
app.PostNewUserFromInvite(nu, ConfirmationKey{newUserDTO: req, completeContactMethods: completeContactMethods}, profile, invite)
/*responseFunc, logFunc, success := app.NewUser(req, false, gc)
if !success {
logFunc()
responseFunc(gc)
return
}*/
code := 200
for _, val := range validation {
if !val {
code = 400
}
}
gc.JSON(code, validation)
// These don't need to complete anytime soon
// wg.Wait()
}
// PostNewUserFromInvite attaches user details (e.g. contact method details) to a new user once they've been created from an invite.
func (app *appContext) PostNewUserFromInvite(nu NewUserData, req ConfirmationKey, profile *Profile, invite Invite) {
nonEmailContactMethodEnabled := false nonEmailContactMethodEnabled := false
for i, c := range req.completeContactMethods { for i, c := range completeContactMethods {
if c.Verified { if c.Verified {
c.User.SetAllowContactFromDTO(req.newUserDTO) c.User.SetAllowContactFromDTO(req)
if c.User.AllowContact() { if c.User.AllowContact() {
nonEmailContactMethodEnabled = true nonEmailContactMethodEnabled = true
} }
@ -264,9 +243,7 @@ func (app *appContext) PostNewUserFromInvite(nu NewUserData, req ConfirmationKey
Addr: req.Email, Addr: req.Email,
Contact: (req.Email != ""), Contact: (req.Email != ""),
Label: invite.UserLabel, Label: invite.UserLabel,
} ReferralTemplateKey: profile.ReferralTemplateKey,
if profile != nil {
profile.ReferralTemplateKey = profile.ReferralTemplateKey
} }
/// Ensures at least one contact method is enabled. /// Ensures at least one contact method is enabled.
if nonEmailContactMethodEnabled { if nonEmailContactMethodEnabled {
@ -280,6 +257,8 @@ func (app *appContext) PostNewUserFromInvite(nu NewUserData, req ConfirmationKey
if !settings["notify-creation"] { if !settings["notify-creation"] {
continue continue
} }
// FIXME: Forgot how "go" works, but these might get killed if not finished
// before we do?
go func(addr string) { go func(addr string) {
msg, err := app.email.constructCreated(req.Code, req.Username, req.Email, invite, app, false) msg, err := app.email.constructCreated(req.Code, req.Username, req.Email, invite, app, false)
if err != nil { if err != nil {
@ -294,7 +273,7 @@ func (app *appContext) PostNewUserFromInvite(nu NewUserData, req ConfirmationKey
if err != nil { if err != nil {
app.err.Printf(lm.FailedSendCreationAdmin, req.Code, addr, err) app.err.Printf(lm.FailedSendCreationAdmin, req.Code, addr, err)
} else { } else {
app.debug.Printf(lm.SentCreationAdmin, req.Code, addr) app.info.Printf(lm.SentCreationAdmin, req.Code, addr)
} }
} }
}(address) }(address)
@ -329,12 +308,12 @@ func (app *appContext) PostNewUserFromInvite(nu NewUserData, req ConfirmationKey
// FIXME: figure these out in a nicer way? this relies on the current ordering, // FIXME: figure these out in a nicer way? this relies on the current ordering,
// which may not be fixed. // which may not be fixed.
if discordEnabled { if discordEnabled {
discordUser = req.completeContactMethods[0].User.(*DiscordUser) discordUser = completeContactMethods[0].User.(*DiscordUser)
if telegramEnabled { if telegramEnabled {
telegramUser = req.completeContactMethods[1].User.(*TelegramUser) telegramUser = completeContactMethods[1].User.(*TelegramUser)
} }
} else if telegramEnabled { } else if telegramEnabled {
telegramUser = req.completeContactMethods[0].User.(*TelegramUser) telegramUser = completeContactMethods[0].User.(*TelegramUser)
} }
} }
@ -343,13 +322,30 @@ func (app *appContext) PostNewUserFromInvite(nu NewUserData, req ConfirmationKey
continue continue
} }
// User already created, now we can link contact methods // User already created, now we can link contact methods
err := tps.AddContactMethods(nu.User.ID, req.newUserDTO, discordUser, telegramUser) err := tps.AddContactMethods(nu.User.ID, req, discordUser, telegramUser)
if err != nil { if err != nil {
app.err.Printf(lm.FailedSyncContactMethods, tps.Name(), err) app.err.Printf(lm.FailedSyncContactMethods, tps.Name(), err)
} }
} }
app.WelcomeNewUser(nu.User, expiry) app.WelcomeNewUser(nu.User, expiry)
/*responseFunc, logFunc, success := app.NewUser(req, false, gc)
if !success {
logFunc()
responseFunc(gc)
return
}*/
code := 200
for _, val := range validation {
if !val {
code = 400
}
}
gc.JSON(code, validation)
// These don't need to complete anytime soon
// wg.Wait()
} }
// @Summary Enable/Disable a list of users, optionally notifying them why. // @Summary Enable/Disable a list of users, optionally notifying them why.

View File

@ -543,8 +543,26 @@
<div class="page-container m-2 lg:my-20 lg:mx-64 flex flex-col gap-4"> <div class="page-container m-2 lg:my-20 lg:mx-64 flex flex-col gap-4">
<div class="top-2 inset-x-2 lg:absolute flex flex-row justify-between"> <div class="top-2 inset-x-2 lg:absolute flex flex-row justify-between">
<div class="flex flex-row gap-2"> <div class="flex flex-row gap-2">
{{ template "lang-select.html" . }} <span class="dropdown z-[11]" tabindex="0" id="lang-dropdown">
<span class="button ~warning h-min" alt="{{ .strings.theme }}" id="button-theme"><i class="ri-sun-line"></i></span> <span class="button ~urge dropdown-button">
<i class="ri-global-line"></i>
<span class="ml-2 chev"></span>
</span>
<div class="dropdown-display">
<div class="card ~neutral @low">
<label class="switch pb-4">
<input type="radio" name="lang-time" id="lang-12h">
<span>{{ .strings.time12h }}</span>
</label>
<label class="switch pb-4">
<input type="radio" name="lang-time" id="lang-24h">
<span>{{ .strings.time24h }}</span>
</label>
<div id="lang-list"></div>
</div>
</div>
</span>
<span class="button ~warning" alt="{{ .strings.theme }}" id="button-theme"><i class="ri-sun-line"></i></span>
</div> </div>
<div class="flex flex-row gap-2"> <div class="flex flex-row gap-2">
<span class="button ~critical @low unfocused" id="logout-button">{{ .strings.logout }}</span> <span class="button ~critical @low unfocused" id="logout-button">{{ .strings.logout }}</span>

View File

@ -35,11 +35,20 @@
</div> </div>
</div> </div>
{{ template "account-linking.html" . }} {{ template "account-linking.html" . }}
<div id="notification-box"></div> <div class="top-2 left-2 absolute">
<div class="page-container m-2 lg:my-20 lg:mx-64 flex flex-col gap-4"> <span class="dropdown" tabindex="0" id="lang-dropdown">
<div class="top-2 inset-x-2 lg:absolute flex flex-row justify-between"> <span class="button ~urge dropdown-button">
{{ template "lang-select.html" . }} <i class="ri-global-line"></i>
<span class="ml-2 chev"></span>
</span>
<div class="dropdown-display">
<div class="card ~neutral @low" id="lang-list">
</div> </div>
</div>
</span>
</div>
<div id="notification-box"></div>
<div class="page-container m-2 lg:my-20 lg:mx-64">
<div class="card dark:~d_neutral @low"> <div class="card dark:~d_neutral @low">
<div class="flex flex-col md:flex-row gap-3 items-baseline mb-2"> <div class="flex flex-col md:flex-row gap-3 items-baseline mb-2">
<span class="heading mr-5"> <span class="heading mr-5">

View File

@ -1,19 +0,0 @@
<span class="dropdown z-[11]" tabindex="0" id="lang-dropdown">
<span class="button ~urge dropdown-button">
<i class="ri-global-line"></i>
<span class="ml-2 chev"></span>
</span>
<div class="dropdown-display">
<div class="card ~neutral @low flex flex-col gap-2">
<label class="switch">
<input type="radio" name="lang-time" id="lang-12h">
<span>{{ .strings.time12h }}</span>
</label>
<label class="switch">
<input type="radio" name="lang-time" id="lang-24h">
<span>{{ .strings.time24h }}</span>
</label>
<div id="lang-list"></div>
</div>
</div>
</span>

View File

@ -10,7 +10,16 @@
<div class="page-container m-2 lg:my-20 lg:mx-64 flex flex-col gap-4"> <div class="page-container m-2 lg:my-20 lg:mx-64 flex flex-col gap-4">
<div class="top-2 inset-x-2 lg:absolute flex flex-row justify-between"> <div class="top-2 inset-x-2 lg:absolute flex flex-row justify-between">
<div class="flex flex-row gap-2"> <div class="flex flex-row gap-2">
{{ template "lang-select.html" . }} <span class="dropdown" tabindex="0" id="lang-dropdown">
<span class="button ~urge dropdown-button">
<i class="ri-global-line"></i>
<span class="ml-2 chev"></span>
</span>
<div class="dropdown-display">
<div class="card ~neutral @low" id="lang-list">
</div>
</div>
</span>
</div> </div>
<span class="button ~warning" alt="{{ .strings.theme }}" id="button-theme"><i class="ri-sun-line"></i></span> <span class="button ~warning" alt="{{ .strings.theme }}" id="button-theme"><i class="ri-sun-line"></i></span>
</div> </div>

View File

@ -80,15 +80,33 @@
{{ template "login-modal.html" . }} {{ template "login-modal.html" . }}
{{ template "account-linking.html" . }} {{ template "account-linking.html" . }}
<div id="notification-box"></div> <div id="notification-box"></div>
<div class="page-container m-2 lg:my-20 lg:mx-64 flex flex-col gap-4 unfocused"> <div class="top-2 left-2 absolute">
<div class="top-2 inset-x-2 lg:absolute flex flex-row justify-between"> <span class="dropdown" tabindex="0" id="lang-dropdown">
<div class="flex flex-row gap-2"> <span class="button ~urge dropdown-button">
{{ template "lang-select.html" . }} <i class="ri-global-line"></i>
<span class="button ~warning h-min" alt="{{ .strings.theme }}" id="button-theme"><i class="ri-sun-line"></i></span> <span class="ml-2 chev"></span>
</span>
<div class="dropdown-display">
<div class="card ~neutral @low">
<label class="switch pb-4">
<input type="radio" name="lang-time" id="lang-12h">
<span>{{ .strings.time12h }}</span>
</label>
<label class="switch pb-4">
<input type="radio" name="lang-time" id="lang-24h">
<span>{{ .strings.time24h }}</span>
</label>
<div id="lang-list"></div>
</div>
</div>
</span>
<span class="button ~warning" alt="{{ .strings.theme }}" id="button-theme"><i class="ri-sun-line"></i></span>
<span class="button ~critical @low mb-4 unfocused" id="logout-button">{{ .strings.logout }}</span> <span class="button ~critical @low mb-4 unfocused" id="logout-button">{{ .strings.logout }}</span>
</div> </div>
<a class="button ~info unfocused h-min" href="/" id="admin-back-button"><i class="ri-arrow-left-fill mr-2"></i>{{ .strings.admin }}</a> <div class="top-2 right-2 absolute">
<a class="button ~info unfocused" href="/" id="admin-back-button"><i class="ri-arrow-left-fill mr-2"></i>{{ .strings.admin }}</a>
</div> </div>
<div class="page-container m-2 lg:my-20 lg:mx-64 unfocused">
<div class="card @low dark:~d_neutral mb-4" id="card-user"> <div class="card @low dark:~d_neutral mb-4" id="card-user">
<span class="heading mb-2"></span> <span class="heading mb-2"></span>
</div> </div>

View File

@ -132,7 +132,7 @@ type appContext struct {
proxyConfig easyproxy.ProxyConfig proxyConfig easyproxy.ProxyConfig
internalPWRs map[string]InternalPWR internalPWRs map[string]InternalPWR
pwrCaptchas map[string]Captcha pwrCaptchas map[string]Captcha
ConfirmationKeys map[string]map[string]ConfirmationKey // Map of invite code to jwt to request ConfirmationKeys map[string]map[string]newUserDTO // Map of invite code to jwt to request
confirmationKeysLock sync.Mutex confirmationKeysLock sync.Mutex
} }

View File

@ -455,14 +455,3 @@ type CreateBackupDTO struct {
type GetBackupsDTO struct { type GetBackupsDTO struct {
Backups []CreateBackupDTO `json:"backups"` Backups []CreateBackupDTO `json:"backups"`
} }
type ConfirmationKey struct {
newUserDTO
completeContactMethods []ContactMethodKey
}
type ContactMethodKey struct {
Verified bool
PIN string
User ContactMethodUser
}

View File

@ -42,7 +42,6 @@ func (app *appContext) ServeSetup(gc *gin.Context) {
gc.HTML(200, "setup.html", gin.H{ gc.HTML(200, "setup.html", gin.H{
"cssVersion": cssVersion, "cssVersion": cssVersion,
"lang": app.storage.lang.Setup[lang], "lang": app.storage.lang.Setup[lang],
"strings": app.storage.lang.Setup[lang].Strings,
"emailLang": app.storage.lang.Email[emailLang], "emailLang": app.storage.lang.Email[emailLang],
"language": app.storage.lang.Setup[lang].JSON, "language": app.storage.lang.Setup[lang].JSON,
"messages": string(msg), "messages": string(msg),

View File

@ -161,7 +161,6 @@ if (window.userExpiryEnabled) {
messageEl.textContent = window.userExpiryMessage.replace("{date}", toDateString(time)); messageEl.textContent = window.userExpiryMessage.replace("{date}", toDateString(time));
setTimeout(calculateTime, 1000); setTimeout(calculateTime, 1000);
}; };
document.addEventListener("timefmt-change", calculateTime)
calculateTime(); calculateTime();
} }

View File

@ -83,7 +83,7 @@ export const loadLangSelector = (page: string) => {
let innerHTML = ''; let innerHTML = '';
for (let code in req.response) { for (let code in req.response) {
queryString.set("lang", code); queryString.set("lang", code);
innerHTML += `<a href="?${queryString.toString()}" class="button w-full text-left justify-start ~neutral lang-link">${req.response[code]}</a>`; innerHTML += `<a href="?${queryString.toString()}" class="button w-full text-left justify-start ~neutral mb-2 lang-link">${req.response[code]}</a>`;
queryString.delete("lang"); queryString.delete("lang");
} }
list.innerHTML = innerHTML; list.innerHTML = innerHTML;

View File

@ -624,7 +624,7 @@ func (app *appContext) NewUserFromConfirmationKey(invite Invite, key string, lan
"contactMessage": app.config.Section("ui").Key("contact_message").String(), "contactMessage": app.config.Section("ui").Key("contact_message").String(),
}) })
} }
var req ConfirmationKey var req newUserDTO
if app.ConfirmationKeys == nil { if app.ConfirmationKeys == nil {
fail() fail()
return return
@ -666,10 +666,8 @@ func (app *appContext) NewUserFromConfirmationKey(invite Invite, key string, lan
profile = &p profile = &p
} }
// FIXME: Email and contract method linking?????
nu /*wg*/, _ := app.NewUserPostVerification(NewUserParams{ nu /*wg*/, _ := app.NewUserPostVerification(NewUserParams{
Req: req.newUserDTO, Req: req,
SourceType: sourceType, SourceType: sourceType,
Source: source, Source: source,
ContextForIPLogging: gc, ContextForIPLogging: gc,
@ -685,8 +683,6 @@ func (app *appContext) NewUserFromConfirmationKey(invite Invite, key string, lan
} }
app.checkInvite(req.Code, true, req.Username) app.checkInvite(req.Code, true, req.Username)
app.PostNewUserFromInvite(nu, req, profile, invite)
jfLink := app.config.Section("ui").Key("redirect_url").String() jfLink := app.config.Section("ui").Key("redirect_url").String()
if app.config.Section("ui").Key("auto_redirect").MustBool(false) { if app.config.Section("ui").Key("auto_redirect").MustBool(false) {
gc.Redirect(301, jfLink) gc.Redirect(301, jfLink)