mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-26 19:10:10 +00:00
Compare commits
3 Commits
bb41bc3844
...
11eb907ced
Author | SHA1 | Date | |
---|---|---|---|
11eb907ced | |||
ea57d657fe | |||
71922212d9 |
82
api-users.go
82
api-users.go
@ -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.
|
||||
|
@ -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>
|
||||
|
@ -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
19
html/lang-select.html
Normal 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>
|
@ -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>
|
||||
|
@ -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>
|
||||
|
2
main.go
2
main.go
@ -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
|
||||
}
|
||||
|
||||
|
11
models.go
11
models.go
@ -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
|
||||
}
|
||||
|
1
setup.go
1
setup.go
@ -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),
|
||||
|
@ -161,6 +161,7 @@ if (window.userExpiryEnabled) {
|
||||
messageEl.textContent = window.userExpiryMessage.replace("{date}", toDateString(time));
|
||||
setTimeout(calculateTime, 1000);
|
||||
};
|
||||
document.addEventListener("timefmt-change", calculateTime)
|
||||
calculateTime();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
8
views.go
8
views.go
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user