mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-11-09 20:00:12 +00:00
Compare commits
3 Commits
c2f835c897
...
729552a827
Author | SHA1 | Date | |
---|---|---|---|
729552a827 | |||
cdc8f9af4b | |||
9e5034ebab |
@ -1,9 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lithammer/shortuuid/v3"
|
||||
"github.com/timshannon/badgerhold/v4"
|
||||
)
|
||||
|
||||
@ -19,13 +21,23 @@ func (app *appContext) GetProfiles(gc *gin.Context) {
|
||||
DefaultProfile: app.storage.GetDefaultProfile().Name,
|
||||
Profiles: map[string]profileDTO{},
|
||||
}
|
||||
referralsEnabled := app.config.Section("user_page").Key("referrals").MustBool(false)
|
||||
baseInv := Invite{}
|
||||
for _, p := range app.storage.GetProfiles() {
|
||||
out.Profiles[p.Name] = profileDTO{
|
||||
Admin: p.Admin,
|
||||
LibraryAccess: p.LibraryAccess,
|
||||
FromUser: p.FromUser,
|
||||
Ombi: p.Ombi != nil,
|
||||
pdto := profileDTO{
|
||||
Admin: p.Admin,
|
||||
LibraryAccess: p.LibraryAccess,
|
||||
FromUser: p.FromUser,
|
||||
Ombi: p.Ombi != nil,
|
||||
ReferralsEnabled: false,
|
||||
}
|
||||
if referralsEnabled {
|
||||
err := app.storage.db.Get(p.ReferralTemplateKey, &baseInv)
|
||||
if p.ReferralTemplateKey != "" && err == nil {
|
||||
pdto.ReferralsEnabled = true
|
||||
}
|
||||
}
|
||||
out.Profiles[p.Name] = pdto
|
||||
}
|
||||
gc.JSON(200, out)
|
||||
}
|
||||
@ -111,3 +123,76 @@ func (app *appContext) DeleteProfile(gc *gin.Context) {
|
||||
app.storage.DeleteProfileKey(name)
|
||||
respondBool(200, true, gc)
|
||||
}
|
||||
|
||||
// @Summary Enable referrals for a profile, sourced from the given invite by its code.
|
||||
// @Produce json
|
||||
// @Param profile path string true "name of profile to enable referrals for."
|
||||
// @Param invite path string true "invite code to create referral template from."
|
||||
// @Success 200 {object} boolResponse
|
||||
// @Failure 400 {object} stringResponse
|
||||
// @Failure 500 {object} stringResponse
|
||||
// @Router /profiles/referral/{profile}/{invite} [post]
|
||||
// @Security Bearer
|
||||
// @tags Profiles & Settings
|
||||
func (app *appContext) EnableReferralForProfile(gc *gin.Context) {
|
||||
profileName := gc.Param("profile")
|
||||
invCode := gc.Param("invite")
|
||||
inv, ok := app.storage.GetInvitesKey(invCode)
|
||||
if !ok {
|
||||
respond(400, "Invalid invite code", gc)
|
||||
app.err.Printf("\"%s\": Failed to enable referrals: invite not found", profileName)
|
||||
return
|
||||
}
|
||||
profile, ok := app.storage.GetProfileKey(profileName)
|
||||
if !ok {
|
||||
respond(400, "Invalid profile", gc)
|
||||
app.err.Printf("\"%s\": Failed to enable referrals: profile not found", profileName)
|
||||
return
|
||||
}
|
||||
|
||||
// Generate new code for referral template
|
||||
inv.Code = shortuuid.New()
|
||||
// make sure code doesn't begin with number
|
||||
_, err := strconv.Atoi(string(inv.Code[0]))
|
||||
for err == nil {
|
||||
inv.Code = shortuuid.New()
|
||||
_, err = strconv.Atoi(string(inv.Code[0]))
|
||||
}
|
||||
inv.Created = time.Now()
|
||||
inv.ValidTill = inv.Created.Add(REFERRAL_EXPIRY_DAYS * 24 * time.Hour)
|
||||
inv.IsReferral = true
|
||||
// Since this is a template for multiple users, ReferrerJellyfinID is not set.
|
||||
// inv.ReferrerJellyfinID = ...
|
||||
|
||||
app.storage.SetInvitesKey(inv.Code, inv)
|
||||
|
||||
profile.ReferralTemplateKey = inv.Code
|
||||
|
||||
app.storage.SetProfileKey(profile.Name, profile)
|
||||
|
||||
respondBool(200, true, gc)
|
||||
}
|
||||
|
||||
// @Summary Disable referrals for a profile, and removes the referral template. no-op if not enabled.
|
||||
// @Produce json
|
||||
// @Param profile path string true "name of profile to enable referrals for."
|
||||
// @Success 200 {object} boolResponse
|
||||
// @Router /profiles/referral/{profile} [delete]
|
||||
// @Security Bearer
|
||||
// @tags Profiles & Settings
|
||||
func (app *appContext) DisableReferralForProfile(gc *gin.Context) {
|
||||
profileName := gc.Param("profile")
|
||||
profile, ok := app.storage.GetProfileKey(profileName)
|
||||
if !ok {
|
||||
respondBool(200, true, gc)
|
||||
return
|
||||
}
|
||||
|
||||
app.storage.DeleteInvitesKey(profile.ReferralTemplateKey)
|
||||
|
||||
profile.ReferralTemplateKey = ""
|
||||
|
||||
app.storage.SetProfileKey(profileName, profile)
|
||||
|
||||
respondBool(200, true, gc)
|
||||
}
|
||||
|
@ -643,10 +643,10 @@ func (app *appContext) GetMyReferral(gc *gin.Context) {
|
||||
// If one exists, that means its just for us and so we
|
||||
// can use it directly.
|
||||
inv := Invite{}
|
||||
err := app.storage.db.Find(&inv, badgerhold.Where("ReferrerJellyfinID").Eq(gc.GetString("jfId")))
|
||||
err := app.storage.db.FindOne(&inv, badgerhold.Where("ReferrerJellyfinID").Eq(gc.GetString("jfId")))
|
||||
if err != nil {
|
||||
// 2. Look for a template matching the key found in the user storage
|
||||
// Since this key is shared between a profile, we make a copy.
|
||||
// Since this key is shared between users in a profile, we make a copy.
|
||||
user, ok := app.storage.GetEmailsKey(gc.GetString("jfId"))
|
||||
err = app.storage.db.Get(user.ReferralTemplateKey, &inv)
|
||||
if !ok || err != nil {
|
||||
@ -664,6 +664,7 @@ func (app *appContext) GetMyReferral(gc *gin.Context) {
|
||||
inv.Created = time.Now()
|
||||
inv.ValidTill = inv.Created.Add(REFERRAL_EXPIRY_DAYS * 24 * time.Hour)
|
||||
inv.IsReferral = true
|
||||
inv.ReferrerJellyfinID = gc.GetString("jfId")
|
||||
app.storage.SetInvitesKey(inv.Code, inv)
|
||||
} else if time.Now().After(inv.ValidTill) {
|
||||
// 3. We found an invite for us, but it's expired.
|
||||
|
28
api-users.go
28
api-users.go
@ -11,6 +11,7 @@ import (
|
||||
"github.com/golang-jwt/jwt"
|
||||
"github.com/hrfee/mediabrowser"
|
||||
"github.com/lithammer/shortuuid/v3"
|
||||
"github.com/timshannon/badgerhold/v4"
|
||||
)
|
||||
|
||||
// @Summary Creates a new Jellyfin user without an invite.
|
||||
@ -657,6 +658,7 @@ func (app *appContext) EnableReferralForUsers(gc *gin.Context) {
|
||||
return
|
||||
|
||||
}
|
||||
app.debug.Printf("Found referral template in profile: %+v\n", profile.ReferralTemplateKey)
|
||||
} else if mode == "invite" {
|
||||
// Get the invite, and modify it to turn it into a referral
|
||||
err := app.storage.db.Get(source, &baseInv)
|
||||
@ -667,6 +669,10 @@ func (app *appContext) EnableReferralForUsers(gc *gin.Context) {
|
||||
}
|
||||
}
|
||||
for _, u := range req.Users {
|
||||
// 1. Wipe out any existing referral codes.
|
||||
app.storage.db.DeleteMatching(Invite{}, badgerhold.Where("ReferrerJellyfinID").Eq(u))
|
||||
|
||||
// 2. Generate referral invite.
|
||||
inv := baseInv
|
||||
inv.Code = shortuuid.New()
|
||||
// make sure code doesn't begin with number
|
||||
@ -887,13 +893,15 @@ func (app *appContext) GetUsers(gc *gin.Context) {
|
||||
}
|
||||
adminOnly := app.config.Section("ui").Key("admin_only").MustBool(true)
|
||||
allowAll := app.config.Section("ui").Key("allow_all").MustBool(false)
|
||||
referralsEnabled := app.config.Section("user_page").Key("referrals").MustBool(false)
|
||||
i := 0
|
||||
for _, jfUser := range users {
|
||||
user := respUser{
|
||||
ID: jfUser.ID,
|
||||
Name: jfUser.Name,
|
||||
Admin: jfUser.Policy.IsAdministrator,
|
||||
Disabled: jfUser.Policy.IsDisabled,
|
||||
ID: jfUser.ID,
|
||||
Name: jfUser.Name,
|
||||
Admin: jfUser.Policy.IsAdministrator,
|
||||
Disabled: jfUser.Policy.IsDisabled,
|
||||
ReferralsEnabled: false,
|
||||
}
|
||||
if !jfUser.LastActivityDate.IsZero() {
|
||||
user.LastActive = jfUser.LastActivityDate.Unix()
|
||||
@ -922,6 +930,18 @@ func (app *appContext) GetUsers(gc *gin.Context) {
|
||||
user.DiscordID = dcUser.ID
|
||||
user.NotifyThroughDiscord = dcUser.Contact
|
||||
}
|
||||
// FIXME: Send referral data
|
||||
referrerInv := Invite{}
|
||||
if referralsEnabled {
|
||||
// 1. Directly attached invite.
|
||||
err := app.storage.db.FindOne(&referrerInv, badgerhold.Where("ReferrerJellyfinID").Eq(jfUser.ID))
|
||||
if err == nil {
|
||||
user.ReferralsEnabled = true
|
||||
// 2. Referrals via profile template. Shallow check, doesn't look for the thing in the database.
|
||||
} else if email, ok := app.storage.GetEmailsKey(jfUser.ID); ok && email.ReferralTemplateKey != "" {
|
||||
user.ReferralsEnabled = true
|
||||
}
|
||||
}
|
||||
resp.UserList[i] = user
|
||||
i++
|
||||
}
|
||||
|
@ -385,7 +385,7 @@
|
||||
"enabled": {
|
||||
"name": "Enabled",
|
||||
"required": false,
|
||||
"requires_restart": false,
|
||||
"requires_restart": true,
|
||||
"type": "bool",
|
||||
"value": true
|
||||
},
|
||||
@ -409,7 +409,7 @@
|
||||
"referrals": {
|
||||
"name": "User Referrals",
|
||||
"required": false,
|
||||
"requires_restart": false,
|
||||
"requires_restart": true,
|
||||
"type": "bool",
|
||||
"value": true,
|
||||
"description": "Users are given their own \"invite\" to send to others."
|
||||
|
@ -135,6 +135,20 @@
|
||||
</label>
|
||||
</form>
|
||||
</div>
|
||||
<div id="modal-enable-referrals-profile" class="modal">
|
||||
<form class="card relative mx-auto my-[10%] w-4/5 lg:w-1/3" id="form-enable-referrals-profile" href="">
|
||||
<span class="heading"><span id="header-enable-referrals-profile">{{ .strings.enableReferrals }}</span> <span class="modal-close">×</span></span>
|
||||
<p class="content my-4">{{ .strings.enableReferralsProfileDescription }}</p>
|
||||
<label class="supra" for="enable-referrals-profile-invites">{{ .strings.invite }}</label>
|
||||
<div class="select ~neutral @low mb-4 mt-2">
|
||||
<select id="enable-referrals-profile-invites"></select>
|
||||
</div>
|
||||
<label>
|
||||
<input type="submit" class="unfocused">
|
||||
<span class="button ~urge @low full-width center supra submit">{{ .strings.apply }}</span>
|
||||
</label>
|
||||
</form>
|
||||
</div>
|
||||
{{ end }}
|
||||
<div id="modal-delete-user" class="modal">
|
||||
<form class="card relative mx-auto my-[10%] w-4/5 lg:w-1/3" id="form-delete-user" href="">
|
||||
@ -332,6 +346,9 @@
|
||||
{{ if .ombiEnabled }}
|
||||
<th>Ombi</th>
|
||||
{{ end }}
|
||||
{{ if .referralsEnabled }}
|
||||
<th>{{ .strings.referrals }}</th>
|
||||
{{ end }}
|
||||
<th>{{ .strings.from }}</th>
|
||||
<th>{{ .strings.userProfilesLibraries }}</th>
|
||||
<th><span class="button ~neutral @high" id="button-profile-create">{{ .strings.create }}</span></th>
|
||||
@ -642,7 +659,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<span class="col button ~urge @low center max-w-[20%]" id="accounts-modify-user">{{ .strings.modifySettings }}</span>
|
||||
<span class="col button ~urge @low center max-w-[20%]" id="accounts-enable-referrals">{{ .strings.enableReferrals }}</span>
|
||||
{{ if .referralsEnabled }}
|
||||
<span class="col button ~urge @low center max-w-[20%]" id="accounts-enable-referrals">{{ .strings.enableReferrals }}</span>
|
||||
{{ end }}
|
||||
<span class="col button ~warning @low center max-w-[20%]" id="accounts-extend-expiry">{{ .strings.extendExpiry }}</span>
|
||||
<div id="accounts-disable-enable-dropdown" class="col dropdown manual pb-0i max-w-[20%]" tabindex="0">
|
||||
<span class="w-100 button ~positive @low center" id="accounts-disable-enable">{{ .strings.disable }}</span>
|
||||
@ -674,6 +693,9 @@
|
||||
{{ if .discordEnabled }}
|
||||
<th class="text-center-i grid gap-4 place-items-stretch accounts-header-discord">Discord</th>
|
||||
{{ end }}
|
||||
{{ if .referralsEnabled }}
|
||||
<th class="text-center-i grid gap-4 place-items-stretch accounts-header-referrals">{{ .strings.referrals }}</th>
|
||||
{{ end }}
|
||||
<th class="grid gap-4 place-items-stretch accounts-header-expiry">{{ .strings.expiry }}</th>
|
||||
<th class="grid gap-4 place-items-stretch accounts-header-last-active">{{ .strings.lastActiveTime }}</th>
|
||||
</tr>
|
||||
|
@ -65,7 +65,8 @@
|
||||
"modifySettings": "Modify Settings",
|
||||
"modifySettingsDescription": "Apply settings from an existing profile, or source them directly from a user.",
|
||||
"enableReferrals": "Enable Referrals",
|
||||
"enableReferralsDescription": "Give users their a referral link similiar to an invite, to send to friends/family. Can be sourced from a referral template in a profile, or from an exsiting invite.",
|
||||
"enableReferralsDescription": "Give users a personal referral link similiar to an invite, to send to friends/family. Can be sourced from a referral template in a profile, or from an existing invite.",
|
||||
"enableReferralsProfileDescription": "Give users created with this profile a personal referral link similiar to an invite, to send to friends/family. Create an invite with the desired settings, then select it here. Each referral will then be based on this invite. You can delete the invite once complete.",
|
||||
"applyHomescreenLayout": "Apply homescreen layout",
|
||||
"sendDeleteNotificationEmail": "Send notification message",
|
||||
"sendDeleteNotifiationExample": "Your account has been deleted.",
|
||||
@ -135,6 +136,7 @@
|
||||
"updateAppliedRefresh": "Update applied, please refresh.",
|
||||
"telegramVerified": "Telegram account verified.",
|
||||
"accountConnected": "Account connected.",
|
||||
"referralsEnabled": "Referrals enabled.",
|
||||
"errorSettingsAppliedNoHomescreenLayout": "Settings were applied, but applying homescreen layout may have failed.",
|
||||
"errorHomescreenAppliedNoSettings": "Homescreen layout was applied, but applying settings may have failed.",
|
||||
"errorSettingsFailed": "Application failed.",
|
||||
|
@ -39,7 +39,8 @@
|
||||
"add": "Add",
|
||||
"edit": "Edit",
|
||||
"delete": "Delete",
|
||||
"myAccount": "My Account"
|
||||
"myAccount": "My Account",
|
||||
"referrals": "Referrals"
|
||||
},
|
||||
"notifications": {
|
||||
"errorLoginBlank": "The username and/or password were left blank.",
|
||||
|
13
models.go
13
models.go
@ -71,10 +71,11 @@ type inviteProfileDTO struct {
|
||||
}
|
||||
|
||||
type profileDTO struct {
|
||||
Admin bool `json:"admin" example:"false"` // Whether profile has admin rights or not
|
||||
LibraryAccess string `json:"libraries" example:"all"` // Number of libraries profile has access to
|
||||
FromUser string `json:"fromUser" example:"jeff"` // The user the profile is based on
|
||||
Ombi bool `json:"ombi"` // Whether or not Ombi settings are stored in this profile.
|
||||
Admin bool `json:"admin" example:"false"` // Whether profile has admin rights or not
|
||||
LibraryAccess string `json:"libraries" example:"all"` // Number of libraries profile has access to
|
||||
FromUser string `json:"fromUser" example:"jeff"` // The user the profile is based on
|
||||
Ombi bool `json:"ombi"` // Whether or not Ombi settings are stored in this profile.
|
||||
ReferralsEnabled bool `json:"referrals_enabled" example:"true"` // Whether or not the profile has referrals enabled, and has a template invite stored.
|
||||
}
|
||||
|
||||
type getProfilesDTO struct {
|
||||
@ -150,6 +151,7 @@ type respUser struct {
|
||||
NotifyThroughMatrix bool `json:"notify_matrix"`
|
||||
Label string `json:"label"` // Label of user, shown next to their name.
|
||||
AccountsAdmin bool `json:"accounts_admin"` // Whether or not the user is a jfa-go admin.
|
||||
ReferralsEnabled bool `json:"referrals_enabled"`
|
||||
}
|
||||
|
||||
type getUsersDTO struct {
|
||||
@ -423,6 +425,5 @@ type GetMyReferralRespDTO struct {
|
||||
}
|
||||
|
||||
type EnableDisableReferralDTO struct {
|
||||
Users []string `json:"users"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Users []string `json:"users"`
|
||||
}
|
||||
|
@ -228,6 +228,8 @@ func (app *appContext) loadRoutes(router *gin.Engine) {
|
||||
api.POST(p+"/matrix/login", app.MatrixLogin)
|
||||
if app.config.Section("user_page").Key("referrals").MustBool(false) {
|
||||
api.POST(p+"/users/referral/:mode/:source", app.EnableReferralForUsers)
|
||||
api.POST(p+"/profiles/referral/:profile/:invite", app.EnableReferralForProfile)
|
||||
api.DELETE(p+"/profiles/referral/:profile", app.DisableReferralForProfile)
|
||||
}
|
||||
|
||||
if userPageEnabled {
|
||||
|
@ -81,6 +81,7 @@ window.availableProfiles = window.availableProfiles || [];
|
||||
|
||||
if (window.referralsEnabled) {
|
||||
window.modals.enableReferralsUser = new Modal(document.getElementById("modal-enable-referrals-user"));
|
||||
window.modals.enableReferralsProfile = new Modal(document.getElementById("modal-enable-referrals-profile"));
|
||||
}
|
||||
})();
|
||||
|
||||
|
@ -23,6 +23,7 @@ interface User {
|
||||
notify_matrix: boolean;
|
||||
label: string;
|
||||
accounts_admin: boolean;
|
||||
referrals_enabled: boolean;
|
||||
}
|
||||
|
||||
interface getPinResponse {
|
||||
@ -69,6 +70,8 @@ class user implements User {
|
||||
private _labelEditButton: HTMLElement;
|
||||
private _accounts_admin: HTMLInputElement
|
||||
private _selected: boolean;
|
||||
private _referralsEnabled: boolean;
|
||||
private _referralsEnabledCheck: HTMLElement;
|
||||
|
||||
lastNotifyMethod = (): string => {
|
||||
// Telegram, Matrix, Discord
|
||||
@ -162,6 +165,17 @@ class user implements User {
|
||||
}
|
||||
}
|
||||
|
||||
get referrals_enabled(): boolean { return this._referralsEnabled; }
|
||||
set referrals_enabled(v: boolean) {
|
||||
this._referralsEnabled = v;
|
||||
if (!window.referralsEnabled) return;
|
||||
if (!v) {
|
||||
this._referralsEnabledCheck.textContent = ``;
|
||||
} else {
|
||||
this._referralsEnabledCheck.innerHTML = `<i class="ri-check-line" aria-label="${window.lang.strings("enabled")}"></i>`;
|
||||
}
|
||||
}
|
||||
|
||||
private _constructDropdown = (): HTMLDivElement => {
|
||||
const el = document.createElement("div") as HTMLDivElement;
|
||||
const telegram = this._telegramUsername != "";
|
||||
@ -506,6 +520,11 @@ class user implements User {
|
||||
<td class="accounts-discord"></td>
|
||||
`;
|
||||
}
|
||||
if (window.referralsEnabled) {
|
||||
innerHTML += `
|
||||
<td class="accounts-referrals text-center-i grid gap-4 place-items-stretch"></td>
|
||||
`;
|
||||
}
|
||||
innerHTML += `
|
||||
<td class="accounts-expiry"></td>
|
||||
<td class="accounts-last-active whitespace-nowrap"></td>
|
||||
@ -545,6 +564,10 @@ class user implements User {
|
||||
};
|
||||
}
|
||||
|
||||
if (window.referralsEnabled) {
|
||||
this._referralsEnabledCheck = this._row.querySelector(".accounts-referrals");
|
||||
}
|
||||
|
||||
this._notifyDropdown = this._constructDropdown();
|
||||
|
||||
const toggleEmailInput = () => {
|
||||
@ -716,6 +739,7 @@ class user implements User {
|
||||
this.discord_id = user.discord_id;
|
||||
this.label = user.label;
|
||||
this.accounts_admin = user.accounts_admin;
|
||||
this.referrals_enabled = user.referrals_enabled;
|
||||
}
|
||||
|
||||
asElement = (): HTMLTableRowElement => { return this._row; }
|
||||
@ -1061,7 +1085,7 @@ export class accountsList {
|
||||
|
||||
let attempt: { year?: number, month?: number, day?: number, hour?: number, minute?: number } = dateParser.attempt(split[1]);
|
||||
// Month in Date objects is 0-based, so make our parsed date that way too
|
||||
if ("month" in attempt) attempt["month"] -= 1;
|
||||
if ("month" in attempt) attempt.month -= 1;
|
||||
|
||||
let date: Date = (Date as any).fromString(split[1]) as Date;
|
||||
console.log("Read", attempt, "and", date);
|
||||
@ -1127,7 +1151,7 @@ export class accountsList {
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
@ -1693,11 +1717,12 @@ export class accountsList {
|
||||
}
|
||||
innerHTML += `<option value="${inv.code}">${name}</option>`;
|
||||
}
|
||||
this._enableReferralsInvite.checked = true;
|
||||
} else {
|
||||
this._enableReferralsInvite.checked = false;
|
||||
this._enableReferralsProfile.checked = true;
|
||||
innerHTML += `<option>${window.lang.strings("inviteNoInvites")}</option>`;
|
||||
}
|
||||
this._enableReferralsProfile.checked = !(this._enableReferralsInvite.checked);
|
||||
this._referralsInviteSelect.innerHTML = innerHTML;
|
||||
|
||||
// 2. Profiles
|
||||
@ -1710,20 +1735,15 @@ export class accountsList {
|
||||
});
|
||||
})();
|
||||
|
||||
// FIXME: Collect Profiles, Invite
|
||||
(() => {
|
||||
})();
|
||||
|
||||
const form = document.getElementById("form-enable-referrals-user") as HTMLFormElement;
|
||||
const button = form.querySelector("span.submit") as HTMLSpanElement;
|
||||
this._enableReferralsProfile.checked = true;
|
||||
this._enableReferralsInvite.checked = false;
|
||||
form.onsubmit = (event: Event) => {
|
||||
event.preventDefault();
|
||||
toggleLoader(button);
|
||||
let send = {
|
||||
"users": list
|
||||
};
|
||||
// console.log("profile:", this._enableReferralsProfile.checked, this._enableReferralsInvite.checked);
|
||||
if (this._enableReferralsProfile.checked && !this._enableReferralsInvite.checked) {
|
||||
send["from"] = "profile";
|
||||
send["profile"] = this._referralsProfileSelect.value;
|
||||
@ -1731,7 +1751,7 @@ export class accountsList {
|
||||
send["from"] = "invite";
|
||||
send["id"] = this._referralsInviteSelect.value;
|
||||
}
|
||||
_post("/users/referrals/" + send["from"] + "/" + send["id"], send, (req: XMLHttpRequest) => {
|
||||
_post("/users/referral/" + send["from"] + "/" + (send["id"] ? send["id"] : send["profile"]), send, (req: XMLHttpRequest) => {
|
||||
if (req.readyState == 4) {
|
||||
toggleLoader(button);
|
||||
if (req.status == 400) {
|
||||
@ -1744,6 +1764,8 @@ export class accountsList {
|
||||
}
|
||||
});
|
||||
};
|
||||
this._enableReferralsProfile.checked = true;
|
||||
this._enableReferralsInvite.checked = false;
|
||||
window.modals.enableReferralsUser.show();
|
||||
}
|
||||
|
||||
@ -1879,10 +1901,10 @@ export class accountsList {
|
||||
this._modifySettingsUser.onchange = checkSource;
|
||||
|
||||
if (window.referralsEnabled) {
|
||||
this._enableReferrals.onclick = this.enableReferrals;
|
||||
const profileSpan = this._enableReferralsProfile.nextElementSibling as HTMLSpanElement;
|
||||
const inviteSpan = this._enableReferralsInvite.nextElementSibling as HTMLSpanElement;
|
||||
const checkReferralSource = () => {
|
||||
console.log("States:", this._enableReferralsProfile.checked, this._enableReferralsInvite.checked);
|
||||
if (this._enableReferralsProfile.checked) {
|
||||
this._referralsInviteSelect.parentElement.classList.add("unfocused");
|
||||
this._referralsProfileSelect.parentElement.classList.remove("unfocused")
|
||||
@ -1899,9 +1921,20 @@ export class accountsList {
|
||||
profileSpan.classList.add("@low");
|
||||
}
|
||||
};
|
||||
this._enableReferralsProfile.onchange = checkReferralSource;
|
||||
this._enableReferralsInvite.onchange = checkReferralSource;
|
||||
checkReferralSource();
|
||||
profileSpan.onclick = () => {
|
||||
this._enableReferralsProfile.checked = true;
|
||||
this._enableReferralsInvite.checked = false;
|
||||
checkReferralSource();
|
||||
};
|
||||
inviteSpan.onclick = () => {;
|
||||
this._enableReferralsInvite.checked = true;
|
||||
this._enableReferralsProfile.checked = false;
|
||||
checkReferralSource();
|
||||
};
|
||||
this._enableReferrals.onclick = () => {
|
||||
this.enableReferrals();
|
||||
profileSpan.onclick(null);
|
||||
};
|
||||
}
|
||||
|
||||
this._deleteUser.onclick = this.deleteUsers;
|
||||
|
@ -5,6 +5,7 @@ interface Profile {
|
||||
libraries: string;
|
||||
fromUser: string;
|
||||
ombi: boolean;
|
||||
referrals_enabled: boolean;
|
||||
}
|
||||
|
||||
class profile implements Profile {
|
||||
@ -16,6 +17,8 @@ class profile implements Profile {
|
||||
private _fromUser: HTMLTableDataCellElement;
|
||||
private _defaultRadio: HTMLInputElement;
|
||||
private _ombi: boolean;
|
||||
private _referralsButton: HTMLSpanElement;
|
||||
private _referralsEnabled: boolean;
|
||||
|
||||
get name(): string { return this._name.textContent; }
|
||||
set name(v: string) { this._name.textContent = v; }
|
||||
@ -52,6 +55,21 @@ class profile implements Profile {
|
||||
get fromUser(): string { return this._fromUser.textContent; }
|
||||
set fromUser(v: string) { this._fromUser.textContent = v; }
|
||||
|
||||
get referrals_enabled(): boolean { return this._referralsEnabled; }
|
||||
set referrals_enabled(v: boolean) {
|
||||
if (!window.referralsEnabled) return;
|
||||
this._referralsEnabled = v;
|
||||
if (v) {
|
||||
this._referralsButton.textContent = window.lang.strings("delete");
|
||||
this._referralsButton.classList.add("~critical");
|
||||
this._referralsButton.classList.remove("~neutral");
|
||||
} else {
|
||||
this._referralsButton.textContent = window.lang.strings("add");
|
||||
this._referralsButton.classList.add("~neutral");
|
||||
this._referralsButton.classList.remove("~critical");
|
||||
}
|
||||
}
|
||||
|
||||
get default(): boolean { return this._defaultRadio.checked; }
|
||||
set default(v: boolean) { this._defaultRadio.checked = v; }
|
||||
|
||||
@ -64,6 +82,9 @@ class profile implements Profile {
|
||||
if (window.ombiEnabled) innerHTML += `
|
||||
<td><span class="button @low profile-ombi"></span></td>
|
||||
`;
|
||||
if (window.referralsEnabled) innerHTML += `
|
||||
<td><span class="button @low profile-referrals"></span></td>
|
||||
`;
|
||||
innerHTML += `
|
||||
<td class="profile-from ellipsis"></td>
|
||||
<td class="profile-libraries"></td>
|
||||
@ -75,6 +96,8 @@ class profile implements Profile {
|
||||
this._libraries = this._row.querySelector("td.profile-libraries") as HTMLTableDataCellElement;
|
||||
if (window.ombiEnabled)
|
||||
this._ombiButton = this._row.querySelector("span.profile-ombi") as HTMLSpanElement;
|
||||
if (window.referralsEnabled)
|
||||
this._referralsButton = this._row.querySelector("span.profile-referrals") as HTMLSpanElement;
|
||||
this._fromUser = this._row.querySelector("td.profile-from") as HTMLTableDataCellElement;
|
||||
this._defaultRadio = this._row.querySelector("input[type=radio]") as HTMLInputElement;
|
||||
this._defaultRadio.onclick = () => document.dispatchEvent(new CustomEvent("profiles-default", { detail: this.name }));
|
||||
@ -89,9 +112,11 @@ class profile implements Profile {
|
||||
this.fromUser = p.fromUser;
|
||||
this.libraries = p.libraries;
|
||||
this.ombi = p.ombi;
|
||||
this.referrals_enabled = p.referrals_enabled;
|
||||
}
|
||||
|
||||
setOmbiFunc = (ombiFunc: (ombi: boolean) => void) => { this._ombiButton.onclick = () => ombiFunc(this._ombi); }
|
||||
setReferralFunc = (referralFunc: (enabled: boolean) => void) => { this._referralsButton.onclick = () => referralFunc(this._referralsEnabled); }
|
||||
|
||||
remove = () => { document.dispatchEvent(new CustomEvent("profiles-delete", { detail: this._name })); this._row.remove(); }
|
||||
|
||||
@ -173,6 +198,14 @@ export class ProfileEditor {
|
||||
this._ombiProfiles.load(name);
|
||||
}
|
||||
});
|
||||
if (window.referralsEnabled)
|
||||
this._profiles[name].setReferralFunc((enabled: boolean) => {
|
||||
if (enabled) {
|
||||
this.disableReferrals(name);
|
||||
} else {
|
||||
this.enableReferrals(name);
|
||||
}
|
||||
});
|
||||
this._table.appendChild(this._profiles[name].asElement());
|
||||
}
|
||||
}
|
||||
@ -185,6 +218,62 @@ export class ProfileEditor {
|
||||
}
|
||||
})
|
||||
|
||||
disableReferrals = (name: string) => _delete("/profiles/referral/" + name, null, (req: XMLHttpRequest) => {
|
||||
if (req.readyState != 4) return;
|
||||
this.load();
|
||||
});
|
||||
|
||||
enableReferrals = (name: string) => {
|
||||
const referralsInviteSelect = document.getElementById("enable-referrals-profile-invites") as HTMLSelectElement;
|
||||
_get("/invites", null, (req: XMLHttpRequest) => {
|
||||
if (req.readyState != 4 || req.status != 200) return;
|
||||
|
||||
let innerHTML = "";
|
||||
let invites = req.response["invites"] as Array<Invite>;
|
||||
window.availableProfiles = req.response["profiles"];
|
||||
if (invites) {
|
||||
for (let inv of invites) {
|
||||
let name = inv.code;
|
||||
if (inv.label) {
|
||||
name = `${inv.label} (${inv.code})`;
|
||||
}
|
||||
innerHTML += `<option value="${inv.code}">${name}</option>`;
|
||||
}
|
||||
} else {
|
||||
innerHTML += `<option>${window.lang.strings("inviteNoInvites")}</option>`;
|
||||
}
|
||||
|
||||
referralsInviteSelect.innerHTML = innerHTML;
|
||||
});
|
||||
|
||||
const form = document.getElementById("form-enable-referrals-profile") as HTMLFormElement;
|
||||
const button = form.querySelector("span.submit") as HTMLSpanElement;
|
||||
form.onsubmit = (event: Event) => {
|
||||
event.preventDefault();
|
||||
toggleLoader(button);
|
||||
|
||||
let send = {
|
||||
"profile": name,
|
||||
"invite": referralsInviteSelect.value
|
||||
};
|
||||
|
||||
_post("/profiles/referral/" + send["profile"] + "/" + send["invite"], send, (req: XMLHttpRequest) => {
|
||||
if (req.readyState == 4) {
|
||||
toggleLoader(button);
|
||||
if (req.status == 400) {
|
||||
window.notifications.customError("unknownError", window.lang.notif("errorUnknown"));
|
||||
} else if (req.status == 200 || req.status == 204) {
|
||||
window.notifications.customSuccess("enableReferralsSuccess", window.lang.notif("referralsEnabled"));
|
||||
}
|
||||
window.modals.enableReferralsProfile.close();
|
||||
this.load();
|
||||
}
|
||||
});
|
||||
};
|
||||
window.modals.profiles.close();
|
||||
window.modals.enableReferralsProfile.show();
|
||||
};
|
||||
|
||||
constructor() {
|
||||
(document.getElementById('setting-profiles') as HTMLSpanElement).onclick = this.load;
|
||||
document.addEventListener("profiles-default", (event: CustomEvent) => {
|
||||
|
@ -115,6 +115,7 @@ declare interface Modals {
|
||||
logs: Modal;
|
||||
email?: Modal;
|
||||
enableReferralsUser?: Modal;
|
||||
enableReferralsProfile?: Modal;
|
||||
}
|
||||
|
||||
interface Invite {
|
||||
|
Loading…
Reference in New Issue
Block a user