mirror of
https://github.com/hrfee/jfa-go.git
synced 2025-01-06 08:20:11 +00:00
Compare commits
2 Commits
a95d8bff29
...
3e55cd1e31
Author | SHA1 | Date | |
---|---|---|---|
3e55cd1e31 | |||
35f0fead53 |
76
api.go
76
api.go
@ -820,6 +820,82 @@ func (app *appContext) Announce(gc *gin.Context) {
|
||||
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.
|
||||
// @Produce json
|
||||
// @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"))))
|
||||
}
|
||||
}
|
||||
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.URLBase = strings.TrimSuffix(app.config.Section("ui").Key("url_base").MustString(""), "/")
|
||||
|
@ -1331,6 +1331,14 @@
|
||||
"type": "text",
|
||||
"value": "",
|
||||
"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%;
|
||||
}
|
||||
|
||||
.h-100 {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.inline-block {
|
||||
display: inline-block;
|
||||
}
|
||||
|
@ -163,15 +163,24 @@
|
||||
<span class="heading"><span id="header-announce"></span> <span class="modal-close">×</span></span>
|
||||
<div class="row">
|
||||
<div class="col flex-col content mt-half">
|
||||
<label class="label supra" for="announce-subject"> {{ .strings.subject }}</label>
|
||||
<input type="text" id="announce-subject" class="input ~neutral !normal mb-1 mt-half">
|
||||
<label class="label supra" for="textarea-announce">{{ .strings.message }}</label>
|
||||
<textarea id="textarea-announce" class="textarea full-width ~neutral !normal mt-half monospace"></textarea>
|
||||
<p class="support mt-half mb-1">{{ .strings.markdownSupported }}</p>
|
||||
<label>
|
||||
<input type="submit" class="unfocused">
|
||||
<span class="button ~urge !normal full-width center supra submit">{{ .strings.submit }}</span>
|
||||
<div id="announce-details">
|
||||
<label class="label supra" for="announce-subject"> {{ .strings.subject }}</label>
|
||||
<input type="text" id="announce-subject" class="input ~neutral !normal mb-1 mt-half">
|
||||
<label class="label supra" for="textarea-announce">{{ .strings.message }}</label>
|
||||
<textarea id="textarea-announce" class="textarea full-width ~neutral !normal mt-half monospace"></textarea>
|
||||
<p class="support mt-half mb-1">{{ .strings.markdownSupported }}</p>
|
||||
</div>
|
||||
<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>
|
||||
<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 class="col card ~neutral !low">
|
||||
<span class="subheading supra">{{ .strings.preview }}</span>
|
||||
@ -542,7 +551,15 @@
|
||||
</div>
|
||||
<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 ~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 ~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>
|
||||
|
@ -48,6 +48,7 @@
|
||||
"unknown": "Unknown",
|
||||
"label": "Label",
|
||||
"announce": "Announce",
|
||||
"templates": "Templates",
|
||||
"subject": "Subject",
|
||||
"message": "Message",
|
||||
"variables": "Variables",
|
||||
@ -100,7 +101,10 @@
|
||||
"searchDiscordUser": "Start typing the Discord username to find the 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.",
|
||||
"matrixHomeServer": "Home server address"
|
||||
"matrixHomeServer": "Home server address",
|
||||
"saveAsTemplate": "Save as template",
|
||||
"deleteTemplate": "Delete template",
|
||||
"templateEnterName": "Enter a name to save this template."
|
||||
},
|
||||
"notifications": {
|
||||
"changedEmailAddress": "Changed email address of {n}.",
|
||||
@ -109,6 +113,7 @@
|
||||
"saveSettings": "Settings were saved",
|
||||
"saveEmail": "Email saved.",
|
||||
"sentAnnouncement": "Announcement sent.",
|
||||
"savedAnnouncement": "Announcement saved.",
|
||||
"setOmbiDefaults": "Stored ombi defaults.",
|
||||
"updateApplied": "Update applied, please restart.",
|
||||
"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 {
|
||||
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.loadProfiles()
|
||||
|
10
models.go
10
models.go
@ -172,6 +172,16 @@ type announcementDTO struct {
|
||||
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 configDTO map[string]interface{}
|
||||
|
@ -163,6 +163,12 @@ func (app *appContext) loadRoutes(router *gin.Engine) {
|
||||
// api.POST(p + "/setDefaults", app.SetDefaults)
|
||||
api.POST(p+"/users/settings", app.ApplySettings)
|
||||
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.POST(p+"/config/update", app.ApplyUpdate)
|
||||
api.GET(p+"/config/emails", app.GetCustomEmails)
|
||||
|
@ -70,21 +70,27 @@ sudo apt-get install jfa-go-tray
|
||||
<p class="row col flex center support">instructions can be found <a target="_blank" href="https://github.com/hrfee/jfa-go#install">here</a></p>
|
||||
<p class="row col flex center support">note: tray icon builds on linux require extra dependencies, see the github README for more info.</p>
|
||||
<div class="row col flex center">
|
||||
<span class="button ~neutral !high mr-1 mb-1 mt-1" id="download-stable">Stable</span>
|
||||
<span class="button ~neutral mb-1 mt-1 mr-1" id="download-unstable">Unstable</span>
|
||||
<span class="button ~neutral !high mr-1 mt-1" id="download-stable">Stable</span>
|
||||
<span class="button ~neutral mt-1 mr-1" id="download-unstable">Unstable</span>
|
||||
</div>
|
||||
<div class="row col flex center" id="sect-stable">
|
||||
<a class="button ~info mr-half mb-half lang-link" target="_blank" href="https://github.com/hrfee/jfa-go/releases">windows/mac/linux</a>
|
||||
<a class="button ~info mr-half mb-half lang-link" id="download-docker">docker</a>
|
||||
<a class="button ~info mr-half mb-half lang-link" id="download-deb">debian/ubuntu</a>
|
||||
<a class="button ~info mr-half mb-half lang-link" target="_blank" href="https://aur.archlinux.org/packages/jfa-go">arch (aur)</a>
|
||||
<a class="button ~info mr-half mb-half lang-link" target="_blank" href="https://aur.archlinux.org/packages/jfa-go-bin">arch (aur binary)</a>
|
||||
<div class="mt-1" id="sect-stable">
|
||||
<p class="row center">Usually released once/twice every month, and aren't necessarily super stable.</p>
|
||||
<div class="row col flex center">
|
||||
<a class="button ~info mr-half mb-half lang-link" target="_blank" href="https://github.com/hrfee/jfa-go/releases">windows/mac/linux</a>
|
||||
<a class="button ~info mr-half mb-half lang-link" id="download-docker">docker</a>
|
||||
<a class="button ~info mr-half mb-half lang-link" id="download-deb">debian/ubuntu</a>
|
||||
<a class="button ~info mr-half mb-half lang-link" target="_blank" href="https://aur.archlinux.org/packages/jfa-go">arch (aur)</a>
|
||||
<a class="button ~info mr-half mb-half lang-link" target="_blank" href="https://aur.archlinux.org/packages/jfa-go-bin">arch (aur binary)</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row col flex center unfocused" id="sect-unstable">
|
||||
<a class="button ~info mr-half mb-half lang-link" target="_blank" href="https://dl.jfa-go.com/view/hrfee/jfa-go">windows/mac/linux</a>
|
||||
<a class="button ~info mr-half mb-half lang-link" id="download-docker-unstable">docker</a>
|
||||
<a class="button ~info mr-half mb-half lang-link" id="download-deb-unstable">debian/ubuntu</a>
|
||||
<a class="button ~info mr-half mb-half lang-link" target="_blank" href="https://aur.archlinux.org/packages/jfa-go-git">arch (aur git)</a>
|
||||
<div class="mt-1 unfocused" id="sect-unstable">
|
||||
<p class="row center">These are built on every commit, so may include incomplete/broken features.</p>
|
||||
<div class="row col flex center">
|
||||
<a class="button ~info mr-half mb-half lang-link" target="_blank" href="https://dl.jfa-go.com/view/hrfee/jfa-go">windows/mac/linux</a>
|
||||
<a class="button ~info mr-half mb-half lang-link" id="download-docker-unstable">docker</a>
|
||||
<a class="button ~info mr-half mb-half lang-link" id="download-deb-unstable">debian/ubuntu</a>
|
||||
<a class="button ~info mr-half mb-half lang-link" target="_blank" href="https://aur.archlinux.org/packages/jfa-go-git">arch (aur git)</a>
|
||||
</div>
|
||||
</div>
|
||||
<section class="section ~neutral banner footer flex-expand middle">
|
||||
<a href="https://github.com/hrfee/jfa-go/blob/main/LICENSE" class="support">© 2021 Harvey Tindall</a>
|
||||
|
41
storage.go
41
storage.go
@ -15,22 +15,23 @@ import (
|
||||
)
|
||||
|
||||
type Storage struct {
|
||||
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
|
||||
users map[string]time.Time
|
||||
invites Invites
|
||||
profiles map[string]Profile
|
||||
defaultProfile string
|
||||
displayprefs, ombi_template map[string]interface{}
|
||||
emails map[string]EmailAddress
|
||||
telegram map[string]TelegramUser // Map of Jellyfin User IDs to telegram 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.
|
||||
customEmails customEmails
|
||||
policy mediabrowser.Policy
|
||||
configuration mediabrowser.Configuration
|
||||
lang Lang
|
||||
invitesLock, usersLock sync.Mutex
|
||||
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, announcements_path string
|
||||
users map[string]time.Time
|
||||
invites Invites
|
||||
profiles map[string]Profile
|
||||
defaultProfile string
|
||||
displayprefs, ombi_template map[string]interface{}
|
||||
emails map[string]EmailAddress
|
||||
telegram map[string]TelegramUser // Map of Jellyfin User IDs to telegram 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.
|
||||
customEmails customEmails
|
||||
policy mediabrowser.Policy
|
||||
configuration mediabrowser.Configuration
|
||||
lang Lang
|
||||
announcements map[string]announcementTemplate
|
||||
invitesLock, usersLock sync.Mutex
|
||||
}
|
||||
|
||||
type TelegramUser struct {
|
||||
@ -839,6 +840,14 @@ func (st *Storage) storeOmbiTemplate() error {
|
||||
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 {
|
||||
err := loadJSON(st.profiles_path, &st.profiles)
|
||||
for name, profile := range st.profiles {
|
||||
|
@ -26,7 +26,13 @@ interface getPinResponse {
|
||||
token: string;
|
||||
username: string;
|
||||
}
|
||||
|
||||
|
||||
interface announcementTemplate {
|
||||
name: string;
|
||||
subject: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
var addDiscord: (passData: string) => void;
|
||||
|
||||
class user implements User {
|
||||
@ -547,6 +553,8 @@ export class accountsList {
|
||||
|
||||
private _addUserButton = document.getElementById("accounts-add-user") 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 _previewLoaded = false;
|
||||
private _announceTextarea = document.getElementById("textarea-announce") as HTMLTextAreaElement;
|
||||
@ -799,16 +807,60 @@ export class accountsList {
|
||||
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");
|
||||
modalHeader.textContent = window.lang.quantity("announceTo", this._collectUsers().length);
|
||||
const form = document.getElementById("form-announce") as HTMLFormElement;
|
||||
let list = this._collectUsers();
|
||||
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;
|
||||
|
||||
subject.value = "";
|
||||
this._announceTextarea.value = "";
|
||||
this._announceNameLabel.classList.add("unfocused");
|
||||
if (template) {
|
||||
subject.value = template.subject;
|
||||
this._announceTextarea.value = template.message;
|
||||
} else {
|
||||
subject.value = "";
|
||||
this._announceTextarea.value = "";
|
||||
}
|
||||
form.onsubmit = (event: Event) => {
|
||||
event.preventDefault();
|
||||
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 = () => {
|
||||
// We can share the delete modal for this
|
||||
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) => {
|
||||
if (req.readyState == 4 && req.status == 200) {
|
||||
// same method as inviteList.reload()
|
||||
let accountsOnDOM: { [id: string]: boolean } = {};
|
||||
for (let id in this._users) { accountsOnDOM[id] = true; }
|
||||
for (let u of (req.response["users"] as User[])) {
|
||||
if (u.id in this._users) {
|
||||
this._users[u.id].update(u);
|
||||
delete accountsOnDOM[u.id];
|
||||
} else {
|
||||
this.add(u);
|
||||
reload = () => {
|
||||
_get("/users", null, (req: XMLHttpRequest) => {
|
||||
if (req.readyState == 4 && req.status == 200) {
|
||||
// same method as inviteList.reload()
|
||||
let accountsOnDOM: { [id: string]: boolean } = {};
|
||||
for (let id in this._users) { accountsOnDOM[id] = true; }
|
||||
for (let u of (req.response["users"] as User[])) {
|
||||
if (u.id in this._users) {
|
||||
this._users[u.id].update(u);
|
||||
delete accountsOnDOM[u.id];
|
||||
} 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();
|
||||
delete this._users[id];
|
||||
}
|
||||
this._checkCheckCount();
|
||||
}
|
||||
})
|
||||
});
|
||||
this.loadTemplates();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user