mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-22 09:00:10 +00:00
accounts: add templates for announcements
you can now save announcements as templates, and then use them later by hovering over the "Announce" button, as well as delete them.
This commit is contained in:
parent
35f0fead53
commit
3e55cd1e31
76
api.go
76
api.go
@ -820,6 +820,82 @@ func (app *appContext) Announce(gc *gin.Context) {
|
|||||||
respondBool(200, true, gc)
|
respondBool(200, true, gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Summary Save an announcement as a template for use or editing later.
|
||||||
|
// @Produce json
|
||||||
|
// @Param announcementTemplate body announcementTemplate true "Announcement request object"
|
||||||
|
// @Success 200 {object} boolResponse
|
||||||
|
// @Failure 500 {object} boolResponse
|
||||||
|
// @Router /users/announce/template [post]
|
||||||
|
// @Security Bearer
|
||||||
|
// @tags Users
|
||||||
|
func (app *appContext) SaveAnnounceTemplate(gc *gin.Context) {
|
||||||
|
var req announcementTemplate
|
||||||
|
gc.BindJSON(&req)
|
||||||
|
if !messagesEnabled {
|
||||||
|
respondBool(400, false, gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
app.storage.announcements[req.Name] = req
|
||||||
|
if err := app.storage.storeAnnouncements(); err != nil {
|
||||||
|
respondBool(500, false, gc)
|
||||||
|
app.err.Printf("Failed to store announcement templates: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
respondBool(200, true, gc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Save an announcement as a template for use or editing later.
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} getAnnouncementsDTO
|
||||||
|
// @Router /users/announce/template [get]
|
||||||
|
// @Security Bearer
|
||||||
|
// @tags Users
|
||||||
|
func (app *appContext) GetAnnounceTemplates(gc *gin.Context) {
|
||||||
|
resp := &getAnnouncementsDTO{make([]string, len(app.storage.announcements))}
|
||||||
|
i := 0
|
||||||
|
for name := range app.storage.announcements {
|
||||||
|
resp.Announcements[i] = name
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
gc.JSON(200, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Get an announcement template.
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} announcementTemplate
|
||||||
|
// @Failure 400 {object} boolResponse
|
||||||
|
// @Param name path string true "name of template"
|
||||||
|
// @Router /users/announce/template/{name} [get]
|
||||||
|
// @Security Bearer
|
||||||
|
// @tags Users
|
||||||
|
func (app *appContext) GetAnnounceTemplate(gc *gin.Context) {
|
||||||
|
name := gc.Param("name")
|
||||||
|
if announcement, ok := app.storage.announcements[name]; ok {
|
||||||
|
gc.JSON(200, announcement)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
respondBool(400, false, gc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Delete an announcement template.
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} boolResponse
|
||||||
|
// @Failure 500 {object} boolResponse
|
||||||
|
// @Param name path string true "name of template"
|
||||||
|
// @Router /users/announce/template/{name} [delete]
|
||||||
|
// @Security Bearer
|
||||||
|
// @tags Users
|
||||||
|
func (app *appContext) DeleteAnnounceTemplate(gc *gin.Context) {
|
||||||
|
name := gc.Param("name")
|
||||||
|
delete(app.storage.announcements, name)
|
||||||
|
if err := app.storage.storeAnnouncements(); err != nil {
|
||||||
|
respondBool(500, false, gc)
|
||||||
|
app.err.Printf("Failed to store announcement templates: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
respondBool(200, false, gc)
|
||||||
|
}
|
||||||
|
|
||||||
// @Summary Create a new invite.
|
// @Summary Create a new invite.
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param generateInviteDTO body generateInviteDTO true "New invite request object"
|
// @Param generateInviteDTO body generateInviteDTO true "New invite request object"
|
||||||
|
@ -44,7 +44,7 @@ func (app *appContext) loadConfig() error {
|
|||||||
key.SetValue(key.MustString(filepath.Join(app.dataPath, (key.Name() + ".json"))))
|
key.SetValue(key.MustString(filepath.Join(app.dataPath, (key.Name() + ".json"))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, key := range []string{"user_configuration", "user_displayprefs", "user_profiles", "ombi_template", "invites", "emails", "user_template", "custom_emails", "users", "telegram_users", "discord_users", "matrix_users"} {
|
for _, key := range []string{"user_configuration", "user_displayprefs", "user_profiles", "ombi_template", "invites", "emails", "user_template", "custom_emails", "users", "telegram_users", "discord_users", "matrix_users", "announcements"} {
|
||||||
app.config.Section("files").Key(key).SetValue(app.config.Section("files").Key(key).MustString(filepath.Join(app.dataPath, (key + ".json"))))
|
app.config.Section("files").Key(key).SetValue(app.config.Section("files").Key(key).MustString(filepath.Join(app.dataPath, (key + ".json"))))
|
||||||
}
|
}
|
||||||
app.URLBase = strings.TrimSuffix(app.config.Section("ui").Key("url_base").MustString(""), "/")
|
app.URLBase = strings.TrimSuffix(app.config.Section("ui").Key("url_base").MustString(""), "/")
|
||||||
|
@ -1331,6 +1331,14 @@
|
|||||||
"type": "text",
|
"type": "text",
|
||||||
"value": "",
|
"value": "",
|
||||||
"description": "Stores discord user IDs and language preferences."
|
"description": "Stores discord user IDs and language preferences."
|
||||||
|
},
|
||||||
|
"announcements": {
|
||||||
|
"name": "Announcement templates",
|
||||||
|
"required": false,
|
||||||
|
"requires_restart": false,
|
||||||
|
"type": "text",
|
||||||
|
"value": "",
|
||||||
|
"description": "Stores custom announcement templates."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,6 +134,10 @@ div.card:contains(section.banner.footer) {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.h-100 {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.inline-block {
|
.inline-block {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
@ -163,15 +163,24 @@
|
|||||||
<span class="heading"><span id="header-announce"></span> <span class="modal-close">×</span></span>
|
<span class="heading"><span id="header-announce"></span> <span class="modal-close">×</span></span>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col flex-col content mt-half">
|
<div class="col flex-col content mt-half">
|
||||||
<label class="label supra" for="announce-subject"> {{ .strings.subject }}</label>
|
<div id="announce-details">
|
||||||
<input type="text" id="announce-subject" class="input ~neutral !normal mb-1 mt-half">
|
<label class="label supra" for="announce-subject"> {{ .strings.subject }}</label>
|
||||||
<label class="label supra" for="textarea-announce">{{ .strings.message }}</label>
|
<input type="text" id="announce-subject" class="input ~neutral !normal mb-1 mt-half">
|
||||||
<textarea id="textarea-announce" class="textarea full-width ~neutral !normal mt-half monospace"></textarea>
|
<label class="label supra" for="textarea-announce">{{ .strings.message }}</label>
|
||||||
<p class="support mt-half mb-1">{{ .strings.markdownSupported }}</p>
|
<textarea id="textarea-announce" class="textarea full-width ~neutral !normal mt-half monospace"></textarea>
|
||||||
<label>
|
<p class="support mt-half mb-1">{{ .strings.markdownSupported }}</p>
|
||||||
<input type="submit" class="unfocused">
|
</div>
|
||||||
<span class="button ~urge !normal full-width center supra submit">{{ .strings.submit }}</span>
|
<label class="label unfocused" id="announce-name"><p class="supra">{{ .strings.name }}</p>
|
||||||
|
<input type="text" class="input ~neutral !normal mb-1 mt-half">
|
||||||
|
<p class="support">{{ .strings.templateEnterName }}</p>
|
||||||
</label>
|
</label>
|
||||||
|
<div class="row flex-expand">
|
||||||
|
<label>
|
||||||
|
<input type="submit" class="unfocused">
|
||||||
|
<span class="button ~urge !normal center supra submit">{{ .strings.send }}</span>
|
||||||
|
</label>
|
||||||
|
<span class="button ~info !normal center supra" id="save-announce">{{ .strings.saveAsTemplate }}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col card ~neutral !low">
|
<div class="col card ~neutral !low">
|
||||||
<span class="subheading supra">{{ .strings.preview }}</span>
|
<span class="subheading supra">{{ .strings.preview }}</span>
|
||||||
@ -542,7 +551,15 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<span class="col sm button ~neutral !normal center mb-half" id="accounts-add-user">{{ .quantityStrings.addUser.Singular }}</span>
|
<span class="col sm button ~neutral !normal center mb-half" id="accounts-add-user">{{ .quantityStrings.addUser.Singular }}</span>
|
||||||
<span class="col sm button ~info !normal center mb-half" id="accounts-announce">{{ .strings.announce }}</span>
|
<div id="accounts-announce-dropdown" class="col sm dropdown" tabindex="0">
|
||||||
|
<span class="h-100 sm button ~info !normal center mb-half" id="accounts-announce">{{ .strings.announce }}</span>
|
||||||
|
<div class="dropdown-display">
|
||||||
|
<div class="card ~neutral !low">
|
||||||
|
<span class="supra sm">{{ .strings.templates }}</span>
|
||||||
|
<div id="accounts-announce-templates"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<span class="col sm button ~urge !normal center mb-half" id="accounts-modify-user">{{ .strings.modifySettings }}</span>
|
<span class="col sm button ~urge !normal center mb-half" id="accounts-modify-user">{{ .strings.modifySettings }}</span>
|
||||||
<span class="col sm button ~warning !normal center mb-half" id="accounts-extend-expiry">{{ .strings.extendExpiry }}</span>
|
<span class="col sm button ~warning !normal center mb-half" id="accounts-extend-expiry">{{ .strings.extendExpiry }}</span>
|
||||||
<span class="col sm button ~positive !normal center mb-half" id="accounts-disable-enable">{{ .strings.disable }}</span>
|
<span class="col sm button ~positive !normal center mb-half" id="accounts-disable-enable">{{ .strings.disable }}</span>
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
"unknown": "Unknown",
|
"unknown": "Unknown",
|
||||||
"label": "Label",
|
"label": "Label",
|
||||||
"announce": "Announce",
|
"announce": "Announce",
|
||||||
|
"templates": "Templates",
|
||||||
"subject": "Subject",
|
"subject": "Subject",
|
||||||
"message": "Message",
|
"message": "Message",
|
||||||
"variables": "Variables",
|
"variables": "Variables",
|
||||||
@ -100,7 +101,10 @@
|
|||||||
"searchDiscordUser": "Start typing the Discord username to find the user.",
|
"searchDiscordUser": "Start typing the Discord username to find the user.",
|
||||||
"findDiscordUser": "Find Discord user",
|
"findDiscordUser": "Find Discord user",
|
||||||
"linkMatrixDescription": "Enter the username and password of the user to use as a bot. Once submitted, the app will restart.",
|
"linkMatrixDescription": "Enter the username and password of the user to use as a bot. Once submitted, the app will restart.",
|
||||||
"matrixHomeServer": "Home server address"
|
"matrixHomeServer": "Home server address",
|
||||||
|
"saveAsTemplate": "Save as template",
|
||||||
|
"deleteTemplate": "Delete template",
|
||||||
|
"templateEnterName": "Enter a name to save this template."
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"changedEmailAddress": "Changed email address of {n}.",
|
"changedEmailAddress": "Changed email address of {n}.",
|
||||||
@ -109,6 +113,7 @@
|
|||||||
"saveSettings": "Settings were saved",
|
"saveSettings": "Settings were saved",
|
||||||
"saveEmail": "Email saved.",
|
"saveEmail": "Email saved.",
|
||||||
"sentAnnouncement": "Announcement sent.",
|
"sentAnnouncement": "Announcement sent.",
|
||||||
|
"savedAnnouncement": "Announcement saved.",
|
||||||
"setOmbiDefaults": "Stored ombi defaults.",
|
"setOmbiDefaults": "Stored ombi defaults.",
|
||||||
"updateApplied": "Update applied, please restart.",
|
"updateApplied": "Update applied, please restart.",
|
||||||
"updateAppliedRefresh": "Update applied, please refresh.",
|
"updateAppliedRefresh": "Update applied, please refresh.",
|
||||||
|
4
main.go
4
main.go
@ -359,6 +359,10 @@ func start(asDaemon, firstCall bool) {
|
|||||||
if err := app.storage.loadMatrixUsers(); err != nil {
|
if err := app.storage.loadMatrixUsers(); err != nil {
|
||||||
app.err.Printf("Failed to load Matrix users: %v", err)
|
app.err.Printf("Failed to load Matrix users: %v", err)
|
||||||
}
|
}
|
||||||
|
app.storage.announcements_path = app.config.Section("files").Key("announcements").String()
|
||||||
|
if err := app.storage.loadAnnouncements(); err != nil {
|
||||||
|
app.err.Printf("Failed to load announcement templates: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
app.storage.profiles_path = app.config.Section("files").Key("user_profiles").String()
|
app.storage.profiles_path = app.config.Section("files").Key("user_profiles").String()
|
||||||
app.storage.loadProfiles()
|
app.storage.loadProfiles()
|
||||||
|
10
models.go
10
models.go
@ -172,6 +172,16 @@ type announcementDTO struct {
|
|||||||
Message string `json:"message"` // Email content (markdown supported)
|
Message string `json:"message"` // Email content (markdown supported)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type announcementTemplate struct {
|
||||||
|
Name string `json:"name"` // Name of template
|
||||||
|
Subject string `json:"subject"` // Email subject
|
||||||
|
Message string `json:"message"` // Email content (markdown supported)
|
||||||
|
}
|
||||||
|
|
||||||
|
type getAnnouncementsDTO struct {
|
||||||
|
Announcements []string `json:"announcements"` // list of announcement names.
|
||||||
|
}
|
||||||
|
|
||||||
type errorListDTO map[string]map[string]string
|
type errorListDTO map[string]map[string]string
|
||||||
|
|
||||||
type configDTO map[string]interface{}
|
type configDTO map[string]interface{}
|
||||||
|
@ -163,6 +163,12 @@ func (app *appContext) loadRoutes(router *gin.Engine) {
|
|||||||
// api.POST(p + "/setDefaults", app.SetDefaults)
|
// api.POST(p + "/setDefaults", app.SetDefaults)
|
||||||
api.POST(p+"/users/settings", app.ApplySettings)
|
api.POST(p+"/users/settings", app.ApplySettings)
|
||||||
api.POST(p+"/users/announce", app.Announce)
|
api.POST(p+"/users/announce", app.Announce)
|
||||||
|
|
||||||
|
api.GET(p+"/users/announce", app.GetAnnounceTemplates)
|
||||||
|
api.POST(p+"/users/announce/template", app.SaveAnnounceTemplate)
|
||||||
|
api.GET(p+"/users/announce/:name", app.GetAnnounceTemplate)
|
||||||
|
api.DELETE(p+"/users/announce/:name", app.DeleteAnnounceTemplate)
|
||||||
|
|
||||||
api.GET(p+"/config/update", app.CheckUpdate)
|
api.GET(p+"/config/update", app.CheckUpdate)
|
||||||
api.POST(p+"/config/update", app.ApplyUpdate)
|
api.POST(p+"/config/update", app.ApplyUpdate)
|
||||||
api.GET(p+"/config/emails", app.GetCustomEmails)
|
api.GET(p+"/config/emails", app.GetCustomEmails)
|
||||||
|
41
storage.go
41
storage.go
@ -15,22 +15,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Storage struct {
|
type Storage struct {
|
||||||
timePattern string
|
timePattern string
|
||||||
invite_path, emails_path, policy_path, configuration_path, displayprefs_path, ombi_path, profiles_path, customEmails_path, users_path, telegram_path, discord_path, matrix_path string
|
invite_path, emails_path, policy_path, configuration_path, displayprefs_path, ombi_path, profiles_path, customEmails_path, users_path, telegram_path, discord_path, matrix_path, announcements_path string
|
||||||
users map[string]time.Time
|
users map[string]time.Time
|
||||||
invites Invites
|
invites Invites
|
||||||
profiles map[string]Profile
|
profiles map[string]Profile
|
||||||
defaultProfile string
|
defaultProfile string
|
||||||
displayprefs, ombi_template map[string]interface{}
|
displayprefs, ombi_template map[string]interface{}
|
||||||
emails map[string]EmailAddress
|
emails map[string]EmailAddress
|
||||||
telegram map[string]TelegramUser // Map of Jellyfin User IDs to telegram users.
|
telegram map[string]TelegramUser // Map of Jellyfin User IDs to telegram users.
|
||||||
discord map[string]DiscordUser // Map of Jellyfin user IDs to discord users.
|
discord map[string]DiscordUser // Map of Jellyfin user IDs to discord users.
|
||||||
matrix map[string]MatrixUser // Map of Jellyfin user IDs to Matrix users.
|
matrix map[string]MatrixUser // Map of Jellyfin user IDs to Matrix users.
|
||||||
customEmails customEmails
|
customEmails customEmails
|
||||||
policy mediabrowser.Policy
|
policy mediabrowser.Policy
|
||||||
configuration mediabrowser.Configuration
|
configuration mediabrowser.Configuration
|
||||||
lang Lang
|
lang Lang
|
||||||
invitesLock, usersLock sync.Mutex
|
announcements map[string]announcementTemplate
|
||||||
|
invitesLock, usersLock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
type TelegramUser struct {
|
type TelegramUser struct {
|
||||||
@ -839,6 +840,14 @@ func (st *Storage) storeOmbiTemplate() error {
|
|||||||
return storeJSON(st.ombi_path, st.ombi_template)
|
return storeJSON(st.ombi_path, st.ombi_template)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (st *Storage) loadAnnouncements() error {
|
||||||
|
return loadJSON(st.announcements_path, &st.announcements)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *Storage) storeAnnouncements() error {
|
||||||
|
return storeJSON(st.announcements_path, st.announcements)
|
||||||
|
}
|
||||||
|
|
||||||
func (st *Storage) loadProfiles() error {
|
func (st *Storage) loadProfiles() error {
|
||||||
err := loadJSON(st.profiles_path, &st.profiles)
|
err := loadJSON(st.profiles_path, &st.profiles)
|
||||||
for name, profile := range st.profiles {
|
for name, profile := range st.profiles {
|
||||||
|
@ -26,7 +26,13 @@ interface getPinResponse {
|
|||||||
token: string;
|
token: string;
|
||||||
username: string;
|
username: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface announcementTemplate {
|
||||||
|
name: string;
|
||||||
|
subject: string;
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
var addDiscord: (passData: string) => void;
|
var addDiscord: (passData: string) => void;
|
||||||
|
|
||||||
class user implements User {
|
class user implements User {
|
||||||
@ -547,6 +553,8 @@ export class accountsList {
|
|||||||
|
|
||||||
private _addUserButton = document.getElementById("accounts-add-user") as HTMLSpanElement;
|
private _addUserButton = document.getElementById("accounts-add-user") as HTMLSpanElement;
|
||||||
private _announceButton = document.getElementById("accounts-announce") as HTMLSpanElement;
|
private _announceButton = document.getElementById("accounts-announce") as HTMLSpanElement;
|
||||||
|
private _announceSaveButton = document.getElementById("save-announce") as HTMLSpanElement;
|
||||||
|
private _announceNameLabel = document.getElementById("announce-name") as HTMLLabelElement;
|
||||||
private _announcePreview: HTMLElement;
|
private _announcePreview: HTMLElement;
|
||||||
private _previewLoaded = false;
|
private _previewLoaded = false;
|
||||||
private _announceTextarea = document.getElementById("textarea-announce") as HTMLTextAreaElement;
|
private _announceTextarea = document.getElementById("textarea-announce") as HTMLTextAreaElement;
|
||||||
@ -799,16 +807,60 @@ export class accountsList {
|
|||||||
this._announcePreview.innerHTML = content;
|
this._announcePreview.innerHTML = content;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
announce = () => {
|
saveAnnouncement = (event: Event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
const form = document.getElementById("form-announce") as HTMLFormElement;
|
||||||
|
const button = form.querySelector("span.submit") as HTMLSpanElement;
|
||||||
|
if (this._announceNameLabel.classList.contains("unfocused")) {
|
||||||
|
this._announceNameLabel.classList.remove("unfocused");
|
||||||
|
form.onsubmit = this.saveAnnouncement;
|
||||||
|
button.textContent = window.lang.get("strings", "saveAsTemplate");
|
||||||
|
this._announceSaveButton.classList.add("unfocused");
|
||||||
|
const details = document.getElementById("announce-details");
|
||||||
|
details.classList.add("unfocused");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const name = (this._announceNameLabel.querySelector("input") as HTMLInputElement).value;
|
||||||
|
if (!name) { return; }
|
||||||
|
const subject = document.getElementById("announce-subject") as HTMLInputElement;
|
||||||
|
let send: announcementTemplate = {
|
||||||
|
name: name,
|
||||||
|
subject: subject.value,
|
||||||
|
message: this._announceTextarea.value
|
||||||
|
}
|
||||||
|
_post("/users/announce/template", send, (req: XMLHttpRequest) => {
|
||||||
|
if (req.readyState == 4) {
|
||||||
|
this.reload();
|
||||||
|
toggleLoader(button);
|
||||||
|
window.modals.announce.close();
|
||||||
|
if (req.status != 200 && req.status != 204) {
|
||||||
|
window.notifications.customError("announcementError", window.lang.notif("errorFailureCheckLogs"));
|
||||||
|
} else {
|
||||||
|
window.notifications.customSuccess("announcementSuccess", window.lang.notif("savedAnnouncement"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
announce = (event?: Event, template?: announcementTemplate) => {
|
||||||
const modalHeader = document.getElementById("header-announce");
|
const modalHeader = document.getElementById("header-announce");
|
||||||
modalHeader.textContent = window.lang.quantity("announceTo", this._collectUsers().length);
|
modalHeader.textContent = window.lang.quantity("announceTo", this._collectUsers().length);
|
||||||
const form = document.getElementById("form-announce") as HTMLFormElement;
|
const form = document.getElementById("form-announce") as HTMLFormElement;
|
||||||
let list = this._collectUsers();
|
let list = this._collectUsers();
|
||||||
const button = form.querySelector("span.submit") as HTMLSpanElement;
|
const button = form.querySelector("span.submit") as HTMLSpanElement;
|
||||||
|
removeLoader(button);
|
||||||
|
button.textContent = window.lang.get("strings", "send");
|
||||||
|
const details = document.getElementById("announce-details");
|
||||||
|
details.classList.remove("unfocused");
|
||||||
|
this._announceSaveButton.classList.remove("unfocused");
|
||||||
const subject = document.getElementById("announce-subject") as HTMLInputElement;
|
const subject = document.getElementById("announce-subject") as HTMLInputElement;
|
||||||
|
this._announceNameLabel.classList.add("unfocused");
|
||||||
subject.value = "";
|
if (template) {
|
||||||
this._announceTextarea.value = "";
|
subject.value = template.subject;
|
||||||
|
this._announceTextarea.value = template.message;
|
||||||
|
} else {
|
||||||
|
subject.value = "";
|
||||||
|
this._announceTextarea.value = "";
|
||||||
|
}
|
||||||
form.onsubmit = (event: Event) => {
|
form.onsubmit = (event: Event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
toggleLoader(button);
|
toggleLoader(button);
|
||||||
@ -853,7 +905,53 @@ export class accountsList {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
loadTemplates = () => _get("/users/announce", null, (req: XMLHttpRequest) => {
|
||||||
|
if (req.readyState == 4) {
|
||||||
|
if (req.status != 200) {
|
||||||
|
this._announceButton.nextElementSibling.children[0].classList.add("unfocused");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._announceButton.nextElementSibling.children[0].classList.remove("unfocused");
|
||||||
|
const list = req.response["announcements"] as string[];
|
||||||
|
if (list.length == 0) {
|
||||||
|
this._announceButton.nextElementSibling.children[0].classList.add("unfocused");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const dList = document.getElementById("accounts-announce-templates") as HTMLDivElement;
|
||||||
|
dList.textContent = '';
|
||||||
|
for (let name of list) {
|
||||||
|
const el = document.createElement("div") as HTMLDivElement;
|
||||||
|
el.classList.add("flex-expand", "ellipsis", "mt-half");
|
||||||
|
el.innerHTML = `
|
||||||
|
<span class="button ~neutral sm full-width accounts-announce-template-button">${name}</span><span class="button ~critical fr ml-1 accounts-announce-template-delete">×</span>
|
||||||
|
`;
|
||||||
|
(el.querySelector("span.accounts-announce-template-button") as HTMLSpanElement).onclick = () => {
|
||||||
|
_get("/users/announce/" + name, null, (req: XMLHttpRequest) => {
|
||||||
|
if (req.readyState == 4) {
|
||||||
|
let template: announcementTemplate;
|
||||||
|
if (req.status != 200) {
|
||||||
|
window.notifications.customError("getTemplateError", window.lang.notif("errorFailureCheckLogs"));
|
||||||
|
} else {
|
||||||
|
template = req.response;
|
||||||
|
}
|
||||||
|
this.announce(null, template);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
(el.querySelector("span.accounts-announce-template-delete") as HTMLSpanElement).onclick = () => {
|
||||||
|
_delete("/users/announce/" + name, null, (req: XMLHttpRequest) => {
|
||||||
|
if (req.readyState == 4) {
|
||||||
|
if (req.status != 200) {
|
||||||
|
window.notifications.customError("deleteTemplateError", window.lang.notif("errorFailureCheckLogs"));
|
||||||
|
}
|
||||||
|
this.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
dList.appendChild(el);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
enableDisableUsers = () => {
|
enableDisableUsers = () => {
|
||||||
// We can share the delete modal for this
|
// We can share the delete modal for this
|
||||||
const modalHeader = document.getElementById("header-delete-user");
|
const modalHeader = document.getElementById("header-delete-user");
|
||||||
@ -1154,26 +1252,31 @@ export class accountsList {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this._announceSaveButton.onclick = this.saveAnnouncement;
|
||||||
}
|
}
|
||||||
|
|
||||||
reload = () => _get("/users", null, (req: XMLHttpRequest) => {
|
reload = () => {
|
||||||
if (req.readyState == 4 && req.status == 200) {
|
_get("/users", null, (req: XMLHttpRequest) => {
|
||||||
// same method as inviteList.reload()
|
if (req.readyState == 4 && req.status == 200) {
|
||||||
let accountsOnDOM: { [id: string]: boolean } = {};
|
// same method as inviteList.reload()
|
||||||
for (let id in this._users) { accountsOnDOM[id] = true; }
|
let accountsOnDOM: { [id: string]: boolean } = {};
|
||||||
for (let u of (req.response["users"] as User[])) {
|
for (let id in this._users) { accountsOnDOM[id] = true; }
|
||||||
if (u.id in this._users) {
|
for (let u of (req.response["users"] as User[])) {
|
||||||
this._users[u.id].update(u);
|
if (u.id in this._users) {
|
||||||
delete accountsOnDOM[u.id];
|
this._users[u.id].update(u);
|
||||||
} else {
|
delete accountsOnDOM[u.id];
|
||||||
this.add(u);
|
} else {
|
||||||
|
this.add(u);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
for (let id in accountsOnDOM) {
|
||||||
|
this._users[id].remove();
|
||||||
|
delete this._users[id];
|
||||||
|
}
|
||||||
|
this._checkCheckCount();
|
||||||
}
|
}
|
||||||
for (let id in accountsOnDOM) {
|
});
|
||||||
this._users[id].remove();
|
this.loadTemplates();
|
||||||
delete this._users[id];
|
}
|
||||||
}
|
|
||||||
this._checkCheckCount();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user