mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-29 12:30:11 +00:00
Compare commits
1 Commits
b0c5f24de3
...
b95eaad2c1
Author | SHA1 | Date | |
---|---|---|---|
|
b95eaad2c1 |
@ -45,24 +45,14 @@ func (app *appContext) checkInvites() {
|
||||
app.storage.SetInvitesKey(data.Code, data)
|
||||
}
|
||||
|
||||
if data.IsReferral && (!data.UseReferralExpiry || data.ReferrerJellyfinID == "") {
|
||||
if data.IsReferral {
|
||||
continue
|
||||
}
|
||||
expiry := data.ValidTill
|
||||
if !currentTime.After(expiry) {
|
||||
continue
|
||||
}
|
||||
|
||||
app.debug.Printf("Housekeeping: Deleting old invite %s", data.Code)
|
||||
|
||||
// Disable referrals for the user if UseReferralExpiry is enabled, so no new ones are made.
|
||||
if data.IsReferral && data.UseReferralExpiry && data.ReferrerJellyfinID != "" {
|
||||
user, ok := app.storage.GetEmailsKey(data.ReferrerJellyfinID)
|
||||
if ok {
|
||||
user.ReferralTemplateKey = ""
|
||||
app.storage.SetEmailsKey(data.ReferrerJellyfinID, user)
|
||||
}
|
||||
}
|
||||
notify := data.Notify
|
||||
if emailEnabled && app.config.Section("notifications").Key("enabled").MustBool(false) && len(notify) != 0 {
|
||||
app.debug.Printf("%s: Expiry notification", data.Code)
|
||||
@ -146,13 +136,6 @@ func (app *appContext) checkInvite(code string, used bool, username string) bool
|
||||
}
|
||||
wait.Wait()
|
||||
}
|
||||
if inv.IsReferral && inv.ReferrerJellyfinID != "" && inv.UseReferralExpiry {
|
||||
user, ok := app.storage.GetEmailsKey(inv.ReferrerJellyfinID)
|
||||
if ok {
|
||||
user.ReferralTemplateKey = ""
|
||||
app.storage.SetEmailsKey(inv.ReferrerJellyfinID, user)
|
||||
}
|
||||
}
|
||||
match = false
|
||||
app.storage.DeleteInvitesKey(code)
|
||||
app.storage.SetActivityKey(shortuuid.New(), Activity{
|
||||
|
@ -36,8 +36,8 @@ func (app *appContext) GetCustomContent(gc *gin.Context) {
|
||||
"WelcomeEmail": {Name: app.storage.lang.Email[lang].WelcomeEmail["name"], Enabled: app.storage.MustGetCustomContentKey("WelcomeEmail").Enabled},
|
||||
"EmailConfirmation": {Name: app.storage.lang.Email[lang].EmailConfirmation["name"], Enabled: app.storage.MustGetCustomContentKey("EmailConfirmation").Enabled},
|
||||
"UserExpired": {Name: app.storage.lang.Email[lang].UserExpired["name"], Enabled: app.storage.MustGetCustomContentKey("UserExpired").Enabled},
|
||||
"UserLogin": {Name: app.storage.lang.Admin[adminLang].Strings["userPageLogin"], Enabled: app.storage.MustGetCustomContentKey("UserLogin").Enabled},
|
||||
"UserPage": {Name: app.storage.lang.Admin[adminLang].Strings["userPagePage"], Enabled: app.storage.MustGetCustomContentKey("UserPage").Enabled},
|
||||
"UserLogin": {Name: app.storage.lang.Admin[adminLang].Strings["userPageLogin"], Enabled: app.storage.MustGetCustomContentKey("Login").Enabled},
|
||||
"UserPage": {Name: app.storage.lang.Admin[adminLang].Strings["userPagePage"], Enabled: app.storage.MustGetCustomContentKey("Page").Enabled},
|
||||
}
|
||||
|
||||
filter := gc.Query("filter")
|
||||
|
@ -130,17 +130,15 @@ func (app *appContext) DeleteProfile(gc *gin.Context) {
|
||||
// @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."
|
||||
// @Param useExpiry path string true "with-expiry or none."
|
||||
// @Success 200 {object} boolResponse
|
||||
// @Failure 400 {object} stringResponse
|
||||
// @Failure 500 {object} stringResponse
|
||||
// @Router /profiles/referral/{profile}/{invite}/{useExpiry} [post]
|
||||
// @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")
|
||||
useExpiry := gc.Param("useExpiry") == "with-expiry"
|
||||
inv, ok := app.storage.GetInvitesKey(invCode)
|
||||
if !ok {
|
||||
respond(400, "Invalid invite code", gc)
|
||||
@ -156,15 +154,9 @@ func (app *appContext) EnableReferralForProfile(gc *gin.Context) {
|
||||
|
||||
// Generate new code for referral template
|
||||
inv.Code = GenerateInviteCode()
|
||||
expiryDelta := inv.ValidTill.Sub(inv.Created)
|
||||
inv.Created = time.Now()
|
||||
if useExpiry {
|
||||
inv.ValidTill = inv.Created.Add(expiryDelta)
|
||||
} else {
|
||||
inv.ValidTill = inv.Created.Add(REFERRAL_EXPIRY_DAYS * 24 * time.Hour)
|
||||
}
|
||||
inv.ValidTill = inv.Created.Add(REFERRAL_EXPIRY_DAYS * 24 * time.Hour)
|
||||
inv.IsReferral = true
|
||||
inv.UseReferralExpiry = useExpiry
|
||||
// Since this is a template for multiple users, ReferrerJellyfinID is not set.
|
||||
// inv.ReferrerJellyfinID = ...
|
||||
|
||||
|
@ -746,37 +746,21 @@ func (app *appContext) GetMyReferral(gc *gin.Context) {
|
||||
// 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 || user.ReferralTemplateKey == "" {
|
||||
if !ok || err != nil {
|
||||
app.debug.Printf("Ignoring referral request, couldn't find template.")
|
||||
respondBool(400, false, gc)
|
||||
return
|
||||
}
|
||||
inv.Code = GenerateInviteCode()
|
||||
expiryDelta := inv.ValidTill.Sub(inv.Created)
|
||||
inv.Created = time.Now()
|
||||
if inv.UseReferralExpiry {
|
||||
inv.ValidTill = inv.Created.Add(expiryDelta)
|
||||
} else {
|
||||
inv.ValidTill = inv.Created.Add(REFERRAL_EXPIRY_DAYS * 24 * time.Hour)
|
||||
}
|
||||
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.
|
||||
// We delete it from storage, and put it back with a fresh code and expiry.
|
||||
// If UseReferralExpiry is enabled, we delete it and return nothing.
|
||||
app.storage.DeleteInvitesKey(inv.Code)
|
||||
if inv.UseReferralExpiry {
|
||||
user, ok := app.storage.GetEmailsKey(gc.GetString("jfId"))
|
||||
if ok {
|
||||
user.ReferralTemplateKey = ""
|
||||
app.storage.SetEmailsKey(gc.GetString("jfId"), user)
|
||||
}
|
||||
app.debug.Printf("Ignoring referral request, expired.")
|
||||
respondBool(400, false, gc)
|
||||
return
|
||||
}
|
||||
inv.Code = GenerateInviteCode()
|
||||
inv.Created = time.Now()
|
||||
inv.ValidTill = inv.Created.Add(REFERRAL_EXPIRY_DAYS * 24 * time.Hour)
|
||||
@ -787,6 +771,5 @@ func (app *appContext) GetMyReferral(gc *gin.Context) {
|
||||
RemainingUses: inv.RemainingUses,
|
||||
NoLimit: inv.NoLimit,
|
||||
Expiry: inv.ValidTill.Unix(),
|
||||
UseExpiry: inv.UseReferralExpiry,
|
||||
})
|
||||
}
|
||||
|
26
api-users.go
26
api-users.go
@ -367,19 +367,6 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
|
||||
emailStore.ReferralTemplateKey = profile.ReferralTemplateKey
|
||||
// Store here, just incase email are disabled (whether this is even possible, i don't know)
|
||||
app.storage.SetEmailsKey(id, emailStore)
|
||||
|
||||
// If UseReferralExpiry is enabled, create the ref now so the clock starts ticking
|
||||
refInv := Invite{}
|
||||
err = app.storage.db.Get(profile.ReferralTemplateKey, &refInv)
|
||||
if refInv.UseReferralExpiry {
|
||||
refInv.Code = GenerateInviteCode()
|
||||
expiryDelta := refInv.ValidTill.Sub(refInv.Created)
|
||||
refInv.Created = time.Now()
|
||||
refInv.ValidTill = refInv.Created.Add(expiryDelta)
|
||||
refInv.IsReferral = true
|
||||
refInv.ReferrerJellyfinID = id
|
||||
app.storage.SetInvitesKey(refInv.Code, refInv)
|
||||
}
|
||||
}
|
||||
}
|
||||
// if app.config.Section("password_resets").Key("enabled").MustBool(false) {
|
||||
@ -742,11 +729,10 @@ func (app *appContext) ExtendExpiry(gc *gin.Context) {
|
||||
// @Param EnableDisableReferralDTO body EnableDisableReferralDTO true "List of users"
|
||||
// @Param mode path string true "mode of template sourcing from 'invite' or 'profile'."
|
||||
// @Param source path string true "invite code or profile name, depending on what mode is."
|
||||
// @Param useExpiry path string true "with-expiry or none."
|
||||
// @Success 200 {object} boolResponse
|
||||
// @Failure 400 {object} boolResponse
|
||||
// @Failure 500 {object} boolResponse
|
||||
// @Router /users/referral/{mode}/{source}/{useExpiry} [post]
|
||||
// @Router /users/referral/{mode}/{source} [post]
|
||||
// @Security Bearer
|
||||
// @tags Users
|
||||
func (app *appContext) EnableReferralForUsers(gc *gin.Context) {
|
||||
@ -754,7 +740,7 @@ func (app *appContext) EnableReferralForUsers(gc *gin.Context) {
|
||||
gc.BindJSON(&req)
|
||||
mode := gc.Param("mode")
|
||||
source := gc.Param("source")
|
||||
useExpiry := gc.Param("useExpiry") == "with-expiry"
|
||||
|
||||
baseInv := Invite{}
|
||||
if mode == "profile" {
|
||||
profile, ok := app.storage.GetProfileKey(source)
|
||||
@ -782,16 +768,10 @@ func (app *appContext) EnableReferralForUsers(gc *gin.Context) {
|
||||
// 2. Generate referral invite.
|
||||
inv := baseInv
|
||||
inv.Code = GenerateInviteCode()
|
||||
expiryDelta := inv.ValidTill.Sub(inv.Created)
|
||||
inv.Created = time.Now()
|
||||
if useExpiry {
|
||||
inv.ValidTill = inv.Created.Add(expiryDelta)
|
||||
} else {
|
||||
inv.ValidTill = inv.Created.Add(REFERRAL_EXPIRY_DAYS * 24 * time.Hour)
|
||||
}
|
||||
inv.ValidTill = inv.Created.Add(REFERRAL_EXPIRY_DAYS * 24 * time.Hour)
|
||||
inv.IsReferral = true
|
||||
inv.ReferrerJellyfinID = u
|
||||
inv.UseReferralExpiry = useExpiry
|
||||
app.storage.SetInvitesKey(inv.Code, inv)
|
||||
}
|
||||
}
|
||||
|
@ -130,11 +130,6 @@
|
||||
<div class="select ~neutral @low mb-4 unfocused">
|
||||
<select id="enable-referrals-user-invites"></select>
|
||||
</div>
|
||||
<label class="switch mb-4">
|
||||
<input type="checkbox" id="enable-referrals-user-expiry">
|
||||
<span>{{ .strings.useInviteExpiry }}</span>
|
||||
<span class="flex flex-row support mt-2">{{ .strings.useInviteExpiryNote }}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="submit" class="unfocused">
|
||||
<span class="button ~urge @low full-width center supra submit">{{ .strings.apply }}</span>
|
||||
@ -149,11 +144,6 @@
|
||||
<div class="select ~neutral @low mb-4 mt-2">
|
||||
<select id="enable-referrals-profile-invites"></select>
|
||||
</div>
|
||||
<label class="switch mb-4">
|
||||
<input type="checkbox" id="enable-referrals-profile-expiry">
|
||||
<span>{{ .strings.useInviteExpiry }}</span>
|
||||
<span class="flex flex-row support mt-2">{{ .strings.useInviteExpiryNote }}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="submit" class="unfocused">
|
||||
<span class="button ~urge @low full-width center supra submit">{{ .strings.apply }}</span>
|
||||
|
@ -155,7 +155,7 @@
|
||||
<div>
|
||||
<div class="card @low dark:~d_neutral unfocused" id="card-referrals">
|
||||
<span class="heading mb-2">{{ .strings.referrals }}</span>
|
||||
<aside class="aside ~neutral my-4 col user-referrals-description"></aside>
|
||||
<aside class="aside ~neutral my-4 col">{{ .strings.referralsDescription }}</aside>
|
||||
<div class="row flex-expand">
|
||||
<div class="user-referrals-info"></div>
|
||||
<div class="grid my-2">
|
||||
|
@ -76,8 +76,6 @@
|
||||
"disableReferrals": "Disable Referrals",
|
||||
"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.",
|
||||
"useInviteExpiry": "Set expiry from profile/invite",
|
||||
"useInviteExpiryNote": "By default, invites expire after 90 days but can be renewed by the user. Enable for the referral to be disabled after the time set.",
|
||||
"applyHomescreenLayout": "Apply homescreen layout",
|
||||
"sendDeleteNotificationEmail": "Send notification message",
|
||||
"sendDeleteNotifiationExample": "Your account has been deleted.",
|
||||
|
@ -36,7 +36,6 @@
|
||||
"resetSentDescription": "If an account with the given username/contact method exists, a password reset link has been sent via all contact methods available. The code will expire in 30 minutes.",
|
||||
"changePassword": "Change Password",
|
||||
"referralsDescription": "Invite friends & family to Jellyfin with this link. Come back here for a new one if it expires.",
|
||||
"referralsWithExpiryDescription": "Invite friends & family to Jellyfin with this link. The link will be disabled once it expires.",
|
||||
"copyReferral": "Copy Link",
|
||||
"invitedBy": "You were invited by user {user}."
|
||||
},
|
||||
|
@ -424,8 +424,7 @@ type GetMyReferralRespDTO struct {
|
||||
Code string `json:"code"`
|
||||
RemainingUses int `json:"remaining_uses"`
|
||||
NoLimit bool `json:"no_limit"`
|
||||
Expiry int64 `json:"expiry"` // Come back after this time to get a new referral (if UseExpiry, a new one can't be made).
|
||||
UseExpiry bool `json:"use_expiry"`
|
||||
Expiry int64 `json:"expiry"` // Come back after this time to get a new referral
|
||||
}
|
||||
|
||||
type EnableDisableReferralDTO struct {
|
||||
|
@ -229,9 +229,9 @@ 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/:useExpiry", app.EnableReferralForUsers)
|
||||
api.POST(p+"/users/referral/:mode/:source", app.EnableReferralForUsers)
|
||||
api.DELETE(p+"/users/referral", app.DisableReferralForUsers)
|
||||
api.POST(p+"/profiles/referral/:profile/:invite/:useExpiry", app.EnableReferralForProfile)
|
||||
api.POST(p+"/profiles/referral/:profile/:invite", app.EnableReferralForProfile)
|
||||
api.DELETE(p+"/profiles/referral/:profile", app.DisableReferralForProfile)
|
||||
}
|
||||
|
||||
|
18
storage.go
18
storage.go
@ -659,15 +659,15 @@ type Invite struct {
|
||||
UserMinutes int `json:"user-minutes,omitempty"`
|
||||
SendTo string `json:"email"`
|
||||
// Used to be stored as formatted time, now as Unix.
|
||||
UsedBy [][]string `json:"used-by"`
|
||||
Notify map[string]map[string]bool `json:"notify"`
|
||||
Profile string `json:"profile"`
|
||||
Label string `json:"label,omitempty"`
|
||||
UserLabel string `json:"user_label,omitempty" example:"Friend"` // Label to apply to users created w/ this invite.
|
||||
Captchas map[string]Captcha // Map of Captcha IDs to images & answers
|
||||
IsReferral bool `json:"is_referral" badgerhold:"index"`
|
||||
ReferrerJellyfinID string `json:"referrer_id"`
|
||||
UseReferralExpiry bool `json:"use_referral_expiry"`
|
||||
UsedBy [][]string `json:"used-by"`
|
||||
Notify map[string]map[string]bool `json:"notify"`
|
||||
Profile string `json:"profile"`
|
||||
Label string `json:"label,omitempty"`
|
||||
UserLabel string `json:"user_label,omitempty" example:"Friend"` // Label to apply to users created w/ this invite.
|
||||
Captchas map[string]Captcha // Map of Captcha IDs to images & answers
|
||||
IsReferral bool `json:"is_referral" badgerhold:"index"`
|
||||
ReferrerJellyfinID string `json:"referrer_id"`
|
||||
ReferrerTemplateForProfile string
|
||||
}
|
||||
|
||||
type Captcha struct {
|
||||
|
@ -783,7 +783,6 @@ export class accountsList {
|
||||
private _userSelect = document.getElementById("modify-user-users") as HTMLSelectElement;
|
||||
private _referralsProfileSelect = document.getElementById("enable-referrals-user-profiles") as HTMLSelectElement;
|
||||
private _referralsInviteSelect = document.getElementById("enable-referrals-user-invites") as HTMLSelectElement;
|
||||
private _referralsExpiry = document.getElementById("enable-referrals-user-expiry") as HTMLInputElement;
|
||||
private _searchBox = document.getElementById("accounts-search") as HTMLInputElement;
|
||||
private _search: Search;
|
||||
|
||||
@ -1579,7 +1578,7 @@ export class accountsList {
|
||||
send["from"] = "invite";
|
||||
send["id"] = this._referralsInviteSelect.value;
|
||||
}
|
||||
_post("/users/referral/" + send["from"] + "/" + (send["id"] ? send["id"] : send["profile"]) + "/" + (this._referralsExpiry.checked ? "with-expiry" : "none"), 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) {
|
||||
@ -1594,7 +1593,6 @@ export class accountsList {
|
||||
};
|
||||
this._enableReferralsProfile.checked = true;
|
||||
this._enableReferralsInvite.checked = false;
|
||||
this._referralsExpiry.checked = false;
|
||||
window.modals.enableReferralsUser.show();
|
||||
}
|
||||
|
||||
|
@ -225,7 +225,6 @@ export class ProfileEditor {
|
||||
|
||||
enableReferrals = (name: string) => {
|
||||
const referralsInviteSelect = document.getElementById("enable-referrals-profile-invites") as HTMLSelectElement;
|
||||
const referralsExpiry = document.getElementById("enable-referrals-profile-expiry") as HTMLInputElement;
|
||||
_get("/invites", null, (req: XMLHttpRequest) => {
|
||||
if (req.readyState != 4 || req.status != 200) return;
|
||||
|
||||
@ -258,7 +257,7 @@ export class ProfileEditor {
|
||||
"invite": referralsInviteSelect.value
|
||||
};
|
||||
|
||||
_post("/profiles/referral/" + send["profile"] + "/" + send["invite"] + "/" + (referralsExpiry.checked ? "with-expiry" : "none"), send, (req: XMLHttpRequest) => {
|
||||
_post("/profiles/referral/" + send["profile"] + "/" + send["invite"], send, (req: XMLHttpRequest) => {
|
||||
if (req.readyState == 4) {
|
||||
toggleLoader(button);
|
||||
if (req.status == 400) {
|
||||
@ -271,7 +270,6 @@ export class ProfileEditor {
|
||||
}
|
||||
});
|
||||
};
|
||||
referralsExpiry.checked = false;
|
||||
window.modals.profiles.close();
|
||||
window.modals.enableReferralsProfile.show();
|
||||
};
|
||||
|
18
ts/user.ts
18
ts/user.ts
@ -116,7 +116,6 @@ interface MyReferral {
|
||||
remaining_uses: number;
|
||||
no_limit: boolean;
|
||||
expiry: number;
|
||||
use_expiry: boolean;
|
||||
}
|
||||
|
||||
interface ContactDTO {
|
||||
@ -253,7 +252,6 @@ class ReferralCard {
|
||||
private _url: string;
|
||||
private _expiry: Date;
|
||||
private _expiryUnix: number;
|
||||
private _useExpiry: boolean;
|
||||
private _remainingUses: number;
|
||||
private _noLimit: boolean;
|
||||
|
||||
@ -261,7 +259,6 @@ class ReferralCard {
|
||||
private _infoArea: HTMLDivElement;
|
||||
private _remainingUsesEl: HTMLSpanElement;
|
||||
private _expiryEl: HTMLSpanElement;
|
||||
private _descriptionEl: HTMLSpanElement;
|
||||
|
||||
get code(): string { return this._code; }
|
||||
set code(c: string) {
|
||||
@ -298,21 +295,10 @@ class ReferralCard {
|
||||
this._expiryEl.textContent = toDateString(this._expiry);
|
||||
}
|
||||
|
||||
get use_expiry(): boolean { return this._useExpiry; }
|
||||
set use_expiry(v: boolean) {
|
||||
this._useExpiry = v;
|
||||
if (v) {
|
||||
this._descriptionEl.textContent = window.lang.strings("referralsWithExpiryDescription");
|
||||
} else {
|
||||
this._descriptionEl.textContent = window.lang.strings("referralsDescription");
|
||||
}
|
||||
}
|
||||
|
||||
constructor(card: HTMLElement) {
|
||||
this._card = card;
|
||||
this._button = this._card.querySelector(".user-referrals-button") as HTMLButtonElement;
|
||||
this._infoArea = this._card.querySelector(".user-referrals-info") as HTMLDivElement;
|
||||
this._descriptionEl = this._card.querySelector(".user-referrals-description") as HTMLSpanElement;
|
||||
|
||||
this._infoArea.innerHTML = `
|
||||
<div class="row my-3">
|
||||
@ -358,7 +344,6 @@ class ReferralCard {
|
||||
this.no_limit = referral.no_limit;
|
||||
this.expiry = referral.expiry;
|
||||
this._card.classList.remove("unfocused");
|
||||
this.use_expiry = referral.use_expiry;
|
||||
};
|
||||
}
|
||||
|
||||
@ -635,8 +620,9 @@ document.addEventListener("details-reload", () => {
|
||||
}
|
||||
}
|
||||
|
||||
messageCard.innerHTML = messageCard.innerHTML.replace(new RegExp("{username}", "g"), details.username);
|
||||
|
||||
if (typeof(messageCard) != "undefined" && messageCard != null) {
|
||||
messageCard.innerHTML = messageCard.innerHTML.replace(new RegExp("{username}", "g"), details.username);
|
||||
setBestRowSpan(messageCard, false);
|
||||
// contactCard.querySelector(".content").classList.add("h-100");
|
||||
} else if (!statusCard.classList.contains("unfocused")) {
|
||||
|
Loading…
Reference in New Issue
Block a user