1
0
mirror of https://github.com/hrfee/jfa-go.git synced 2024-12-26 19:10:10 +00:00

Compare commits

...

3 Commits

Author SHA1 Message Date
11eb907ced
html/css: fix overlap of top button row on some pages
row with language, light/dark, logout etc. was overlapping with content
on small screens on some pages, as I forgot to bring over changes made
to the admin page. Also improved some other CSS, and factored out the
language menu into html/lang-select.html.
2024-10-11 17:08:14 +01:00
ea57d657fe
form: fix contact details/profile application when using email
confirmation

my rewrite of account-creation stuff had a massive oversight of email
confirmation, the steps done after account creation (email and contact
method storage, referral stuff) were not done on the email confirmation
path. This has been factored out to PostNewUserFromIvnite, and the
ConfirmationKeys store now includes the newUserDTO and the list of
completeContactMethods.
2024-10-11 16:38:19 +01:00
71922212d9
form: fix account creation with no profile
missing "profile != nil" check.
2024-10-11 11:46:40 +01:00
12 changed files with 98 additions and 112 deletions

View File

@ -110,11 +110,7 @@ func (app *appContext) NewUserFromInvite(gc *gin.Context) {
gc.JSON(200, validation)
return
}
completeContactMethods := make([]struct {
Verified bool
PIN string
User ContactMethodUser
}, len(app.contactMethods))
completeContactMethods := make([]ContactMethodKey, len(app.contactMethods))
for i, cm := range app.contactMethods {
completeContactMethods[i].PIN = cm.PIN(req)
if completeContactMethods[i].PIN == "" {
@ -168,13 +164,16 @@ func (app *appContext) NewUserFromInvite(gc *gin.Context) {
return
}
if app.ConfirmationKeys == nil {
app.ConfirmationKeys = map[string]map[string]newUserDTO{}
app.ConfirmationKeys = map[string]map[string]ConfirmationKey{}
}
cKeys, ok := app.ConfirmationKeys[req.Code]
if !ok {
cKeys = map[string]newUserDTO{}
cKeys = map[string]ConfirmationKey{}
}
cKeys[key] = ConfirmationKey{
newUserDTO: req,
completeContactMethods: completeContactMethods,
}
cKeys[key] = req
app.confirmationKeysLock.Lock()
app.ConfirmationKeys[req.Code] = cKeys
app.confirmationKeysLock.Unlock()
@ -187,7 +186,7 @@ func (app *appContext) NewUserFromInvite(gc *gin.Context) {
} else if err := app.email.send(msg, req.Email); err != nil {
app.err.Printf(lm.FailedSendConfirmationEmail, req.Code, req.Email, err)
} else {
app.err.Printf(lm.SentConfirmationEmail, req.Code, req.Email)
app.debug.Printf(lm.SentConfirmationEmail, req.Code, req.Email)
}
return
}
@ -223,10 +222,32 @@ func (app *appContext) NewUserFromInvite(gc *gin.Context) {
}
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
for i, c := range completeContactMethods {
for i, c := range req.completeContactMethods {
if c.Verified {
c.User.SetAllowContactFromDTO(req)
c.User.SetAllowContactFromDTO(req.newUserDTO)
if c.User.AllowContact() {
nonEmailContactMethodEnabled = true
}
@ -240,10 +261,12 @@ func (app *appContext) NewUserFromInvite(gc *gin.Context) {
if (emailEnabled && req.Email != "") || invite.UserLabel != "" || referralsEnabled {
emailStore := EmailAddress{
Addr: req.Email,
Contact: (req.Email != ""),
Label: invite.UserLabel,
ReferralTemplateKey: profile.ReferralTemplateKey,
Addr: req.Email,
Contact: (req.Email != ""),
Label: invite.UserLabel,
}
if profile != nil {
profile.ReferralTemplateKey = profile.ReferralTemplateKey
}
/// Ensures at least one contact method is enabled.
if nonEmailContactMethodEnabled {
@ -257,8 +280,6 @@ func (app *appContext) NewUserFromInvite(gc *gin.Context) {
if !settings["notify-creation"] {
continue
}
// FIXME: Forgot how "go" works, but these might get killed if not finished
// before we do?
go func(addr string) {
msg, err := app.email.constructCreated(req.Code, req.Username, req.Email, invite, app, false)
if err != nil {
@ -273,7 +294,7 @@ func (app *appContext) NewUserFromInvite(gc *gin.Context) {
if err != nil {
app.err.Printf(lm.FailedSendCreationAdmin, req.Code, addr, err)
} else {
app.info.Printf(lm.SentCreationAdmin, req.Code, addr)
app.debug.Printf(lm.SentCreationAdmin, req.Code, addr)
}
}
}(address)
@ -308,12 +329,12 @@ func (app *appContext) NewUserFromInvite(gc *gin.Context) {
// FIXME: figure these out in a nicer way? this relies on the current ordering,
// which may not be fixed.
if discordEnabled {
discordUser = completeContactMethods[0].User.(*DiscordUser)
discordUser = req.completeContactMethods[0].User.(*DiscordUser)
if telegramEnabled {
telegramUser = completeContactMethods[1].User.(*TelegramUser)
telegramUser = req.completeContactMethods[1].User.(*TelegramUser)
}
} else if telegramEnabled {
telegramUser = completeContactMethods[0].User.(*TelegramUser)
telegramUser = req.completeContactMethods[0].User.(*TelegramUser)
}
}
@ -322,30 +343,13 @@ func (app *appContext) NewUserFromInvite(gc *gin.Context) {
continue
}
// User already created, now we can link contact methods
err := tps.AddContactMethods(nu.User.ID, req, discordUser, telegramUser)
err := tps.AddContactMethods(nu.User.ID, req.newUserDTO, discordUser, telegramUser)
if err != nil {
app.err.Printf(lm.FailedSyncContactMethods, tps.Name(), err)
}
}
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.

View File

@ -543,26 +543,8 @@
<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="flex flex-row gap-2">
<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">
<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>
{{ template "lang-select.html" . }}
<span class="button ~warning h-min" alt="{{ .strings.theme }}" id="button-theme"><i class="ri-sun-line"></i></span>
</div>
<div class="flex flex-row gap-2">
<span class="button ~critical @low unfocused" id="logout-button">{{ .strings.logout }}</span>

View File

@ -35,20 +35,11 @@
</div>
</div>
{{ template "account-linking.html" . }}
<div class="top-2 left-2 absolute">
<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 id="notification-box"></div>
<div class="page-container m-2 lg:my-20 lg:mx-64">
<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">
{{ template "lang-select.html" . }}
</div>
<div class="card dark:~d_neutral @low">
<div class="flex flex-col md:flex-row gap-3 items-baseline mb-2">
<span class="heading mr-5">

19
html/lang-select.html Normal file
View File

@ -0,0 +1,19 @@
<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,16 +10,7 @@
<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="flex flex-row gap-2">
<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>
{{ template "lang-select.html" . }}
</div>
<span class="button ~warning" alt="{{ .strings.theme }}" id="button-theme"><i class="ri-sun-line"></i></span>
</div>

View File

@ -80,33 +80,15 @@
{{ template "login-modal.html" . }}
{{ template "account-linking.html" . }}
<div id="notification-box"></div>
<div class="top-2 left-2 absolute">
<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">
<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 class="page-container m-2 lg:my-20 lg:mx-64 flex flex-col gap-4 unfocused">
<div class="top-2 inset-x-2 lg:absolute flex flex-row justify-between">
<div class="flex flex-row gap-2">
{{ template "lang-select.html" . }}
<span class="button ~warning h-min" 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>
</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>
</div>
<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 class="page-container m-2 lg:my-20 lg:mx-64 unfocused">
<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>
<div class="card @low dark:~d_neutral mb-4" id="card-user">
<span class="heading mb-2"></span>
</div>

View File

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

View File

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

View File

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

View File

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

View File

@ -83,7 +83,7 @@ export const loadLangSelector = (page: string) => {
let innerHTML = '';
for (let code in req.response) {
queryString.set("lang", code);
innerHTML += `<a href="?${queryString.toString()}" class="button w-full text-left justify-start ~neutral mb-2 lang-link">${req.response[code]}</a>`;
innerHTML += `<a href="?${queryString.toString()}" class="button w-full text-left justify-start ~neutral lang-link">${req.response[code]}</a>`;
queryString.delete("lang");
}
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(),
})
}
var req newUserDTO
var req ConfirmationKey
if app.ConfirmationKeys == nil {
fail()
return
@ -666,8 +666,10 @@ func (app *appContext) NewUserFromConfirmationKey(invite Invite, key string, lan
profile = &p
}
// FIXME: Email and contract method linking?????
nu /*wg*/, _ := app.NewUserPostVerification(NewUserParams{
Req: req,
Req: req.newUserDTO,
SourceType: sourceType,
Source: source,
ContextForIPLogging: gc,
@ -683,6 +685,8 @@ func (app *appContext) NewUserFromConfirmationKey(invite Invite, key string, lan
}
app.checkInvite(req.Code, true, req.Username)
app.PostNewUserFromInvite(nu, req, profile, invite)
jfLink := app.config.Section("ui").Key("redirect_url").String()
if app.config.Section("ui").Key("auto_redirect").MustBool(false) {
gc.Redirect(301, jfLink)