import { _get , _post , _delete , toggleLoader , addLoader , removeLoader , toDateString , insertText } from "../modules/common.js" ;
import { templateEmail } from "../modules/settings.js" ;
import { Marked } from "@ts-stack/markdown" ;
import { stripMarkdown } from "../modules/stripmd.js" ;
import { DiscordUser , newDiscordSearch } from "../modules/discord.js" ;
interface User {
id : string ;
name : string ;
email : string | undefined ;
notify_email : boolean ;
last_active : number ;
admin : boolean ;
disabled : boolean ;
expiry : number ;
telegram : string ;
notify_telegram : boolean ;
discord : string ;
notify_discord : boolean ;
discord_id : string ;
matrix : string ;
notify_matrix : boolean ;
}
interface getPinResponse {
token : string ;
username : string ;
}
interface announcementTemplate {
name : string ;
subject : string ;
message : string ;
}
var addDiscord : ( passData : string ) = > void ;
class user implements User {
private _row : HTMLTableRowElement ;
private _check : HTMLInputElement ;
private _username : HTMLSpanElement ;
private _admin : HTMLSpanElement ;
private _disabled : HTMLSpanElement ;
private _email : HTMLInputElement ;
private _notifyEmail : boolean ;
private _emailAddress : string ;
private _emailEditButton : HTMLElement ;
private _telegram : HTMLTableDataCellElement ;
private _telegramUsername : string ;
private _notifyTelegram : boolean ;
private _discord : HTMLTableDataCellElement ;
private _discordUsername : string ;
private _discordID : string ;
private _notifyDiscord : boolean ;
private _matrix : HTMLTableDataCellElement ;
private _matrixID : string ;
private _notifyMatrix : boolean ;
private _expiry : HTMLTableDataCellElement ;
private _expiryUnix : number ;
private _lastActive : HTMLTableDataCellElement ;
private _lastActiveUnix : number ;
private _notifyDropdown : HTMLDivElement ;
id = "" ;
private _selected : boolean ;
private _lastNotifyMethod = ( ) : string = > {
// Telegram, Matrix, Discord
const telegram = window . telegramEnabled && this . _telegramUsername && this . _telegramUsername != "" ;
const discord = window . discordEnabled && this . _discordUsername && this . _discordUsername != "" ;
const matrix = window . matrixEnabled && this . _matrixID && this . _matrixID != "" ;
if ( discord ) return "discord" ;
if ( matrix ) return "matrix" ;
if ( telegram ) return "telegram" ;
}
get selected ( ) : boolean { return this . _selected ; }
set selected ( state : boolean ) {
this . _selected = state ;
this . _check . checked = state ;
state ? document . dispatchEvent ( this . _checkEvent ) : document . dispatchEvent ( this . _uncheckEvent ) ;
}
get name ( ) : string { return this . _username . textContent ; }
set name ( value : string ) { this . _username . textContent = value ; }
get admin ( ) : boolean { return this . _admin . classList . contains ( "chip" ) ; }
set admin ( state : boolean ) {
if ( state ) {
this . _admin . classList . add ( "chip" , "~info" , "ml-1" ) ;
this . _admin . textContent = window . lang . strings ( "admin" ) ;
} else {
this . _admin . classList . remove ( "chip" , "~info" , "ml-1" ) ;
this . _admin . textContent = "" ;
}
}
get disabled ( ) : boolean { return this . _disabled . classList . contains ( "chip" ) ; }
set disabled ( state : boolean ) {
if ( state ) {
this . _disabled . classList . add ( "chip" , "~warning" , "ml-1" ) ;
this . _disabled . textContent = window . lang . strings ( "disabled" ) ;
} else {
this . _disabled . classList . remove ( "chip" , "~warning" , "ml-1" ) ;
this . _disabled . textContent = "" ;
}
}
get email ( ) : string { return this . _emailAddress ; }
set email ( value : string ) {
this . _emailAddress = value ;
const input = this . _email . querySelector ( "input" ) ;
if ( input ) {
input . value = value ;
} else {
this . _email . textContent = value ;
}
}
get notify_email ( ) : boolean { return this . _notifyEmail ; }
set notify_email ( s : boolean ) {
if ( this . _notifyDropdown ) {
( this . _notifyDropdown . querySelector ( ".accounts-contact-email" ) as HTMLInputElement ) . checked = s ;
}
}
private _constructDropdown = ( ) : HTMLDivElement = > {
const el = document . createElement ( "div" ) as HTMLDivElement ;
const telegram = this . _telegramUsername != "" ;
const discord = this . _discordUsername != "" ;
const matrix = this . _matrixID != "" ;
if ( ! telegram && ! discord && ! matrix ) return ;
let innerHTML = `
< i class = "icon ri-settings-2-line ml-half dropdown-button" > < / i >
< div class = "dropdown manual" >
< div class = "dropdown-display lg" >
< div class = "card ~neutral !low" >
< span class = "supra sm" > $ { window . lang . strings ( "contactThrough" ) } < / span >
< label class = "row switch pb-1 mt-half" >
< input type = "checkbox" name = "accounts-contact-${this.id}" class = "accounts-contact-email" >
< / span > Email < / span >
< / label >
< div class = "accounts-area-telegram" >
< label class = "row switch pb-1" >
< input type = "checkbox" name = "accounts-contact-${this.id}" class = "accounts-contact-telegram" >
< span > Telegram < / span >
< / label >
< / div >
< div class = "accounts-area-discord" >
< label class = "row switch pb-1" >
< input type = "checkbox" name = "accounts-contact-${this.id}" class = "accounts-contact-discord" >
< span > Discord < / span >
< / label >
< / div >
< div class = "accounts-area-matrix" >
< label class = "row switch pb-1" >
< input type = "checkbox" name = "accounts-contact-${this.id}" class = "accounts-contact-matrix" >
< span > Matrix < / span >
< / label >
< / div >
< / div >
< / div >
< / div >
` ;
el . innerHTML = innerHTML ;
const button = el . querySelector ( "i" ) ;
const dropdown = el . querySelector ( "div.dropdown" ) as HTMLDivElement ;
const checks = el . querySelectorAll ( "input" ) as NodeListOf < HTMLInputElement > ;
for ( let i = 0 ; i < checks . length ; i ++ ) {
checks [ i ] . onclick = ( ) = > this . _setNotifyMethod ( ) ;
}
button . onclick = ( ) = > {
dropdown . classList . add ( "selected" ) ;
document . addEventListener ( "click" , outerClickListener ) ;
} ;
const outerClickListener = ( event : Event ) = > {
if ( ! ( event . target instanceof HTMLElement && ( el . contains ( event . target ) || button . contains ( event . target ) ) ) ) {
dropdown . classList . remove ( "selected" ) ;
document . removeEventListener ( "click" , outerClickListener ) ;
}
} ;
return el ;
}
get matrix ( ) : string { return this . _matrixID ; }
set matrix ( u : string ) {
if ( ! window . matrixEnabled ) {
this . _notifyDropdown . querySelector ( ".accounts-area-matrix" ) . classList . add ( "unfocused" ) ;
return ;
}
const lastNotifyMethod = this . _lastNotifyMethod ( ) == "matrix" ;
this . _matrixID = u ;
if ( ! u ) {
this . _notifyDropdown . querySelector ( ".accounts-area-matrix" ) . classList . add ( "unfocused" ) ;
this . _matrix . innerHTML = `
< span class = "chip btn !low" > $ { window . lang . strings ( "add" ) } < / span >
< input type = "text" class = "input ~neutral !normal stealth-input unfocused" placeholder = "@user:riot.im" >
` ;
( this . _matrix . querySelector ( "span" ) as HTMLSpanElement ) . onclick = this . _addMatrix ;
} else {
this . _notifyDropdown . querySelector ( ".accounts-area-matrix" ) . classList . remove ( "unfocused" ) ;
this . _matrix . innerHTML = `
< div class = "table-inline" >
$ { u }
< / div >
` ;
if ( lastNotifyMethod ) {
( this . _matrix . querySelector ( ".table-inline" ) as HTMLDivElement ) . appendChild ( this . _notifyDropdown ) ;
}
}
}
private _addMatrix = ( ) = > {
const addButton = this . _matrix . querySelector ( ".btn" ) as HTMLSpanElement ;
const icon = this . _matrix . querySelector ( "i" ) ;
const input = this . _matrix . querySelector ( "input.stealth-input" ) as HTMLInputElement ;
if ( addButton . classList . contains ( "chip" ) ) {
input . classList . remove ( "unfocused" ) ;
addButton . innerHTML = ` <i class="ri-check-line"></i> ` ;
addButton . classList . remove ( "chip" )
if ( icon ) {
icon . classList . add ( "unfocused" ) ;
}
} else {
if ( input . value . charAt ( 0 ) != "@" || ! input . value . includes ( ":" ) ) return ;
const send = {
jf_id : this.id ,
user_id : input.value
}
_post ( "/users/matrix" , send , ( req : XMLHttpRequest ) = > {
if ( req . readyState == 4 ) {
document . dispatchEvent ( new CustomEvent ( "accounts-reload" ) ) ;
if ( req . status != 200 ) {
window . notifications . customError ( "errorConnectMatrix" , window . lang . notif ( "errorFailureCheckLogs" ) ) ;
return ;
}
window . notifications . customSuccess ( "connectMatrix" , window . lang . notif ( "accountConnected" ) ) ;
}
} ) ;
}
}
get notify_matrix ( ) : boolean { return this . _notifyMatrix ; }
set notify_matrix ( s : boolean ) {
if ( this . _notifyDropdown ) {
( this . _notifyDropdown . querySelector ( ".accounts-contact-matrix" ) as HTMLInputElement ) . checked = s ;
}
}
get telegram ( ) : string { return this . _telegramUsername ; }
set telegram ( u : string ) {
if ( ! window . telegramEnabled ) {
this . _notifyDropdown . querySelector ( ".accounts-area-telegram" ) . classList . add ( "unfocused" ) ;
return ;
}
const lastNotifyMethod = this . _lastNotifyMethod ( ) == "telegram" ;
this . _telegramUsername = u ;
if ( ! u ) {
this . _notifyDropdown . querySelector ( ".accounts-area-telegram" ) . classList . add ( "unfocused" ) ;
this . _telegram . innerHTML = ` <span class="chip btn !low"> ${ window . lang . strings ( "add" ) } </span> ` ;
( this . _telegram . querySelector ( "span" ) as HTMLSpanElement ) . onclick = this . _addTelegram ;
} else {
this . _notifyDropdown . querySelector ( ".accounts-area-telegram" ) . classList . remove ( "unfocused" ) ;
this . _telegram . innerHTML = `
< div class = "table-inline" >
< a href = "https://t.me/${u}" target = "_blank" > @ $ { u } < / a >
< / div >
` ;
if ( lastNotifyMethod ) {
( this . _telegram . querySelector ( ".table-inline" ) as HTMLDivElement ) . appendChild ( this . _notifyDropdown ) ;
}
}
}
get notify_telegram ( ) : boolean { return this . _notifyTelegram ; }
set notify_telegram ( s : boolean ) {
if ( this . _notifyDropdown ) {
( this . _notifyDropdown . querySelector ( ".accounts-contact-telegram" ) as HTMLInputElement ) . checked = s ;
}
}
private _setNotifyMethod = ( ) = > {
const email = this . _notifyDropdown . getElementsByClassName ( "accounts-contact-email" ) [ 0 ] as HTMLInputElement ;
let send = {
id : this.id ,
email : email.checked
}
if ( window . telegramEnabled && this . _telegramUsername ) {
const telegram = this . _notifyDropdown . getElementsByClassName ( "accounts-contact-telegram" ) [ 0 ] as HTMLInputElement ;
send [ "telegram" ] = telegram . checked ;
}
if ( window . discordEnabled && this . _discordUsername ) {
const discord = this . _notifyDropdown . getElementsByClassName ( "accounts-contact-discord" ) [ 0 ] as HTMLInputElement ;
send [ "discord" ] = discord . checked ;
}
_post ( "/users/contact" , send , ( req : XMLHttpRequest ) = > {
if ( req . readyState == 4 ) {
if ( req . status != 200 ) {
window . notifications . customError ( "errorSetNotify" , window . lang . notif ( "errorSaveSettings" ) ) ;
document . dispatchEvent ( new CustomEvent ( "accounts-reload" ) ) ;
return ;
}
}
} , false , ( req : XMLHttpRequest ) = > {
if ( req . status == 0 ) {
window . notifications . connectionError ( ) ;
document . dispatchEvent ( new CustomEvent ( "accounts-reload" ) ) ;
return ;
} else if ( req . status == 401 ) {
window . notifications . customError ( "401Error" , window . lang . notif ( "error401Unauthorized" ) ) ;
document . dispatchEvent ( new CustomEvent ( "accounts-reload" ) ) ;
}
} ) ;
}
get discord ( ) : string { return this . _discordUsername ; }
set discord ( u : string ) {
if ( ! window . discordEnabled ) {
this . _notifyDropdown . querySelector ( ".accounts-area-discord" ) . classList . add ( "unfocused" ) ;
return ;
}
const lastNotifyMethod = this . _lastNotifyMethod ( ) == "discord" ;
this . _discordUsername = u ;
if ( ! u ) {
this . _discord . innerHTML = ` <span class="chip btn !low">Add</span> ` ;
( this . _discord . querySelector ( "span" ) as HTMLSpanElement ) . onclick = ( ) = > addDiscord ( this . id ) ;
this . _notifyDropdown . querySelector ( ".accounts-area-discord" ) . classList . add ( "unfocused" ) ;
} else {
this . _notifyDropdown . querySelector ( ".accounts-area-discord" ) . classList . remove ( "unfocused" ) ;
this . _discord . innerHTML = `
< div class = "table-inline" >
< a href = "https://discord.com/users/${this._discordID}" class = "discord-link" target = "_blank" > $ { u } < / a >
< / div >
` ;
if ( lastNotifyMethod ) {
( this . _discord . querySelector ( ".table-inline" ) as HTMLDivElement ) . appendChild ( this . _notifyDropdown ) ;
}
}
}
get discord_id ( ) : string { return this . _discordID ; }
set discord_id ( id : string ) {
if ( ! window . discordEnabled || this . _discordUsername == "" ) return ;
this . _discordID = id ;
const link = this . _discord . getElementsByClassName ( "discord-link" ) [ 0 ] as HTMLAnchorElement ;
link . href = ` https://discord.com/users/ ${ id } ` ;
}
get notify_discord ( ) : boolean { return this . _notifyDiscord ; }
set notify_discord ( s : boolean ) {
if ( this . _notifyDropdown ) {
( this . _notifyDropdown . querySelector ( ".accounts-contact-discord" ) as HTMLInputElement ) . checked = s ;
}
}
get expiry ( ) : number { return this . _expiryUnix ; }
set expiry ( unix : number ) {
this . _expiryUnix = unix ;
if ( unix == 0 ) {
this . _expiry . textContent = "" ;
} else {
this . _expiry . textContent = toDateString ( new Date ( unix * 1000 ) ) ;
}
}
get last_active ( ) : number { return this . _lastActiveUnix ; }
set last_active ( unix : number ) {
this . _lastActiveUnix = unix ;
if ( unix == 0 ) {
this . _lastActive . textContent == "n/a" ;
} else {
this . _lastActive . textContent = toDateString ( new Date ( unix * 1000 ) ) ;
}
}
private _checkEvent = new CustomEvent ( "accountCheckEvent" ) ;
private _uncheckEvent = new CustomEvent ( "accountUncheckEvent" ) ;
constructor ( user : User ) {
this . _row = document . createElement ( "tr" ) as HTMLTableRowElement ;
let innerHTML = `
< td > < input type = "checkbox" value = "" > < / td >
< td > < div class = "table-inline" > < span class = "accounts-username" > < / span > < span class = "accounts-admin" > < / span > < span class = "accounts-disabled" > < / span > < / span > < / td >
< td > < div class = "table-inline" > < i class = "icon ri-edit-line accounts-email-edit" > < / i > < span class = "accounts-email-container ml-half" > < / span > < / div > < / td >
` ;
if ( window . telegramEnabled ) {
innerHTML += `
< td class = "accounts-telegram" > < / td >
` ;
}
if ( window . matrixEnabled ) {
innerHTML += `
< td class = "accounts-matrix" > < / td >
` ;
}
if ( window . discordEnabled ) {
innerHTML += `
< td class = "accounts-discord" > < / td >
` ;
}
innerHTML += `
< td class = "accounts-expiry" > < / td >
< td class = "accounts-last-active" > < / td >
` ;
this . _row . innerHTML = innerHTML ;
const emailEditor = ` <input type="email" class="input ~neutral !normal stealth-input"> ` ;
this . _check = this . _row . querySelector ( "input[type=checkbox]" ) as HTMLInputElement ;
this . _username = this . _row . querySelector ( ".accounts-username" ) as HTMLSpanElement ;
this . _admin = this . _row . querySelector ( ".accounts-admin" ) as HTMLSpanElement ;
this . _disabled = this . _row . querySelector ( ".accounts-disabled" ) as HTMLSpanElement ;
this . _email = this . _row . querySelector ( ".accounts-email-container" ) as HTMLInputElement ;
this . _emailEditButton = this . _row . querySelector ( ".accounts-email-edit" ) as HTMLElement ;
this . _telegram = this . _row . querySelector ( ".accounts-telegram" ) as HTMLTableDataCellElement ;
this . _discord = this . _row . querySelector ( ".accounts-discord" ) as HTMLTableDataCellElement ;
this . _matrix = this . _row . querySelector ( ".accounts-matrix" ) as HTMLTableDataCellElement ;
this . _expiry = this . _row . querySelector ( ".accounts-expiry" ) as HTMLTableDataCellElement ;
this . _lastActive = this . _row . querySelector ( ".accounts-last-active" ) as HTMLTableDataCellElement ;
this . _check . onchange = ( ) = > { this . selected = this . _check . checked ; }
this . _notifyDropdown = this . _constructDropdown ( ) ;
const toggleStealthInput = ( ) = > {
if ( this . _emailEditButton . classList . contains ( "ri-edit-line" ) ) {
this . _email . innerHTML = emailEditor ;
this . _email . querySelector ( "input" ) . value = this . _emailAddress ;
this . _email . classList . remove ( "ml-half" ) ;
} else {
this . _email . textContent = this . _emailAddress ;
this . _email . classList . add ( "ml-half" ) ;
}
this . _emailEditButton . classList . toggle ( "ri-check-line" ) ;
this . _emailEditButton . classList . toggle ( "ri-edit-line" ) ;
} ;
const outerClickListener = ( event : Event ) = > {
if ( ! ( event . target instanceof HTMLElement && ( this . _email . contains ( event . target ) || this . _emailEditButton . contains ( event . target ) ) ) ) {
toggleStealthInput ( ) ;
this . email = this . email ;
document . removeEventListener ( "click" , outerClickListener ) ;
}
} ;
this . _emailEditButton . onclick = ( ) = > {
if ( this . _emailEditButton . classList . contains ( "ri-edit-line" ) ) {
document . addEventListener ( 'click' , outerClickListener ) ;
} else {
this . _updateEmail ( ) ;
document . removeEventListener ( 'click' , outerClickListener ) ;
}
toggleStealthInput ( ) ;
} ;
this . update ( user ) ;
document . addEventListener ( "timefmt-change" , ( ) = > {
this . expiry = this . expiry ;
this . last_active = this . last_active ;
} ) ;
}
private _updateEmail = ( ) = > {
let oldEmail = this . email ;
this . email = this . _email . querySelector ( "input" ) . value ;
let send = { } ;
send [ this . id ] = this . email ;
_post ( "/users/emails" , send , ( req : XMLHttpRequest ) = > {
if ( req . readyState == 4 ) {
if ( req . status == 200 ) {
window . notifications . customSuccess ( "emailChanged" , window . lang . var ( "notifications" , "changedEmailAddress" , ` " ${ this . name } " ` ) ) ;
} else {
this . email = oldEmail ;
window . notifications . customError ( "emailChanged" , window . lang . var ( "notifications" , "errorChangedEmailAddress" , ` " ${ this . name } " ` ) ) ;
}
}
} ) ;
}
private _addTelegram = ( ) = > _get ( "/telegram/pin" , null , ( req : XMLHttpRequest ) = > {
if ( req . readyState == 4 && req . status == 200 ) {
const pin = document . getElementById ( "telegram-pin" ) ;
const link = document . getElementById ( "telegram-link" ) as HTMLAnchorElement ;
const username = document . getElementById ( "telegram-username" ) as HTMLSpanElement ;
const waiting = document . getElementById ( "telegram-waiting" ) as HTMLSpanElement ;
let resp = req . response as getPinResponse ;
pin . textContent = resp . token ;
link . href = "https://t.me/" + resp . username ;
username . textContent = resp . username ;
addLoader ( waiting ) ;
let modalClosed = false ;
window . modals . telegram . onclose = ( ) = > {
modalClosed = true ;
removeLoader ( waiting ) ;
}
let send = {
token : resp.token ,
id : this.id
} ;
const checkVerified = ( ) = > _post ( "/users/telegram" , send , ( req : XMLHttpRequest ) = > {
if ( req . readyState == 4 ) {
if ( req . status == 200 && req . response [ "success" ] as boolean ) {
removeLoader ( waiting ) ;
waiting . classList . add ( "~positive" ) ;
waiting . classList . remove ( "~info" ) ;
window . notifications . customSuccess ( "telegramVerified" , window . lang . notif ( "telegramVerified" ) ) ;
setTimeout ( ( ) = > {
window . modals . telegram . close ( ) ;
waiting . classList . add ( "~info" ) ;
waiting . classList . remove ( "~positive" ) ;
} , 2000 ) ;
document . dispatchEvent ( new CustomEvent ( "accounts-reload" ) ) ;
} else if ( ! modalClosed ) {
setTimeout ( checkVerified , 1500 ) ;
}
}
} , true ) ;
window . modals . telegram . show ( ) ;
checkVerified ( ) ;
}
} ) ;
update = ( user : User ) = > {
this . id = user . id ;
this . name = user . name ;
this . email = user . email || "" ;
// Little hack to get settings cogs to appear on first load
this . _discordUsername = user . discord ;
this . _telegramUsername = user . telegram ;
this . _matrixID = user . matrix ;
this . discord = user . discord ;
this . telegram = user . telegram ;
this . matrix = user . matrix ;
this . last_active = user . last_active ;
this . admin = user . admin ;
this . disabled = user . disabled ;
this . expiry = user . expiry ;
this . notify_discord = user . notify_discord ;
this . notify_telegram = user . notify_telegram ;
this . notify_matrix = user . notify_matrix ;
this . notify_email = user . notify_email ;
this . discord_id = user . discord_id ;
}
asElement = ( ) : HTMLTableRowElement = > { return this . _row ; }
remove = ( ) = > {
if ( this . selected ) {
document . dispatchEvent ( this . _uncheckEvent ) ;
}
this . _row . remove ( ) ;
}
}
export class accountsList {
private _table = document . getElementById ( "accounts-list" ) as HTMLTableSectionElement ;
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 ;
private _deleteUser = document . getElementById ( "accounts-delete-user" ) as HTMLSpanElement ;
private _disableEnable = document . getElementById ( "accounts-disable-enable" ) as HTMLSpanElement ;
private _deleteNotify = document . getElementById ( "delete-user-notify" ) as HTMLInputElement ;
private _deleteReason = document . getElementById ( "textarea-delete-user" ) as HTMLTextAreaElement ;
private _extendExpiry = document . getElementById ( "accounts-extend-expiry" ) as HTMLSpanElement ;
private _modifySettings = document . getElementById ( "accounts-modify-user" ) as HTMLSpanElement ;
private _modifySettingsProfile = document . getElementById ( "radio-use-profile" ) as HTMLInputElement ;
private _modifySettingsUser = document . getElementById ( "radio-use-user" ) as HTMLInputElement ;
private _profileSelect = document . getElementById ( "modify-user-profiles" ) as HTMLSelectElement ;
private _userSelect = document . getElementById ( "modify-user-users" ) as HTMLSelectElement ;
private _search = document . getElementById ( "accounts-search" ) as HTMLInputElement ;
private _selectAll = document . getElementById ( "accounts-select-all" ) as HTMLInputElement ;
private _users : { [ id : string ] : user } ;
private _sortedByName : string [ ] = [ ] ;
private _checkCount : number = 0 ;
private _inSearch = false ;
// Whether the enable/disable button should enable or not.
private _shouldEnable = false ;
private _addUserForm = document . getElementById ( "form-add-user" ) as HTMLFormElement ;
private _addUserName = this . _addUserForm . querySelector ( "input[type=text]" ) as HTMLInputElement ;
private _addUserEmail = this . _addUserForm . querySelector ( "input[type=email]" ) as HTMLInputElement ;
private _addUserPassword = this . _addUserForm . querySelector ( "input[type=password]" ) as HTMLInputElement ;
private _count = 30 ;
private _populateNumbers = ( ) = > {
const fieldIDs = [ "months" , "days" , "hours" , "minutes" ] ;
const prefixes = [ "extend-expiry-" ] ;
for ( let i = 0 ; i < fieldIDs . length ; i ++ ) {
for ( let j = 0 ; j < prefixes . length ; j ++ ) {
const field = document . getElementById ( prefixes [ j ] + fieldIDs [ i ] ) ;
field . textContent = '' ;
for ( let n = 0 ; n <= this . _count ; n ++ ) {
const opt = document . createElement ( "option" ) as HTMLOptionElement ;
opt . textContent = "" + n ;
opt . value = "" + n ;
field . appendChild ( opt ) ;
}
}
}
}
search = ( query : string ) : string [ ] = > {
query = query . toLowerCase ( )
let result : string [ ] = [ ] ;
if ( query . includes ( ":" ) ) { // Support admin:<true/false> and disabled:<true/false>
const words = query . split ( " " ) ;
query = "" ;
for ( let word of words ) {
if ( word . includes ( ":" ) ) {
const querySplit = word . split ( ":" )
let state = false ;
if ( querySplit [ 1 ] == "true" ) {
state = true ;
}
for ( let id in this . _users ) {
const user = this . _users [ id ] ;
let attrib : boolean ;
if ( querySplit [ 0 ] == "admin" ) { attrib = user . admin ; }
else if ( querySplit [ 0 ] == "disabled" ) { attrib = user . disabled ; }
if ( attrib == state ) { result . push ( id ) ; }
}
} else { query += word + " " ; }
}
}
if ( query == "" ) { return result ; }
for ( let id in this . _users ) {
const user = this . _users [ id ] ;
if ( user . name . toLowerCase ( ) . includes ( query ) ) {
result . push ( id ) ;
} else if ( user . email . toLowerCase ( ) . includes ( query ) ) {
result . push ( id ) ;
}
}
return result ;
}
get selectAll ( ) : boolean { return this . _selectAll . checked ; }
set selectAll ( state : boolean ) {
let count = 0 ;
for ( let id in this . _users ) {
if ( this . _table . contains ( this . _users [ id ] . asElement ( ) ) ) { // Only select visible elements
this . _users [ id ] . selected = state ;
count ++ ;
}
}
this . _selectAll . checked = state ;
this . _selectAll . indeterminate = false ;
state ? this . _checkCount = count : 0 ;
}
add = ( u : User ) = > {
let domAccount = new user ( u ) ;
this . _users [ u . id ] = domAccount ;
this . unhide ( u . id ) ;
}
unhide = ( id : string ) = > {
const keys = Object . keys ( this . _users ) ;
if ( keys . length == 0 ) {
this . _table . appendChild ( this . _users [ id ] . asElement ( ) ) ;
return ;
}
this . _sortedByName = keys . sort ( ( a , b ) = > this . _users [ a ] . name . localeCompare ( this . _users [ b ] . name ) ) ;
let index = this . _sortedByName . indexOf ( id ) + 1 ;
if ( index == this . _sortedByName . length - 1 ) {
this . _table . appendChild ( this . _users [ id ] . asElement ( ) ) ;
return ;
}
while ( index < this . _sortedByName . length ) {
if ( this . _table . contains ( this . _users [ this . _sortedByName [ index ] ] . asElement ( ) ) ) {
this . _table . insertBefore ( this . _users [ id ] . asElement ( ) , this . _users [ this . _sortedByName [ index ] ] . asElement ( ) ) ;
return ;
}
index ++ ;
}
this . _table . appendChild ( this . _users [ id ] . asElement ( ) ) ;
}
hide = ( id : string ) = > {
const el = this . _users [ id ] . asElement ( ) ;
if ( this . _table . contains ( el ) ) {
this . _table . removeChild ( this . _users [ id ] . asElement ( ) ) ;
}
}
private _checkCheckCount = ( ) = > {
const list = this . _collectUsers ( ) ;
this . _checkCount = list . length ;
if ( this . _checkCount == 0 ) {
this . _selectAll . indeterminate = false ;
this . _selectAll . checked = false ;
this . _modifySettings . classList . add ( "unfocused" ) ;
this . _deleteUser . classList . add ( "unfocused" ) ;
if ( window . emailEnabled || window . telegramEnabled ) {
this . _announceButton . classList . add ( "unfocused" ) ;
}
this . _extendExpiry . classList . add ( "unfocused" ) ;
this . _disableEnable . classList . add ( "unfocused" ) ;
} else {
let visibleCount = 0 ;
for ( let id in this . _users ) {
if ( this . _table . contains ( this . _users [ id ] . asElement ( ) ) ) {
visibleCount ++ ;
}
}
if ( this . _checkCount == visibleCount ) {
this . _selectAll . checked = true ;
this . _selectAll . indeterminate = false ;
} else {
this . _selectAll . checked = false ;
this . _selectAll . indeterminate = true ;
}
this . _modifySettings . classList . remove ( "unfocused" ) ;
this . _deleteUser . classList . remove ( "unfocused" ) ;
this . _deleteUser . textContent = window . lang . quantity ( "deleteUser" , list . length ) ;
if ( window . emailEnabled || window . telegramEnabled ) {
this . _announceButton . classList . remove ( "unfocused" ) ;
}
let anyNonExpiries = list . length == 0 ? true : false ;
// Only show enable/disable button if all selected have the same state.
this . _shouldEnable = this . _users [ list [ 0 ] ] . disabled
let showDisableEnable = true ;
for ( let id of list ) {
if ( ! anyNonExpiries && ! this . _users [ id ] . expiry ) {
anyNonExpiries = true ;
this . _extendExpiry . classList . add ( "unfocused" ) ;
}
if ( showDisableEnable && this . _users [ id ] . disabled != this . _shouldEnable ) {
showDisableEnable = false ;
this . _disableEnable . classList . add ( "unfocused" ) ;
}
if ( ! showDisableEnable && anyNonExpiries ) { break ; }
}
if ( ! anyNonExpiries ) {
this . _extendExpiry . classList . remove ( "unfocused" ) ;
}
if ( showDisableEnable ) {
let message : string ;
if ( this . _shouldEnable ) {
message = window . lang . strings ( "reEnable" ) ;
this . _disableEnable . classList . add ( "~positive" ) ;
this . _disableEnable . classList . remove ( "~warning" ) ;
} else {
message = window . lang . strings ( "disable" ) ;
this . _disableEnable . classList . add ( "~warning" ) ;
this . _disableEnable . classList . remove ( "~positive" ) ;
}
this . _disableEnable . classList . remove ( "unfocused" ) ;
this . _disableEnable . textContent = message ;
}
}
}
private _collectUsers = ( ) : string [ ] = > {
let list : string [ ] = [ ] ;
for ( let id in this . _users ) {
if ( this . _table . contains ( this . _users [ id ] . asElement ( ) ) && this . _users [ id ] . selected ) { list . push ( id ) ; }
}
return list ;
}
private _addUser = ( event : Event ) = > {
event . preventDefault ( ) ;
const button = this . _addUserForm . querySelector ( "span.submit" ) as HTMLSpanElement ;
const send = {
"username" : this . _addUserName . value ,
"email" : this . _addUserEmail . value ,
"password" : this . _addUserPassword . value
} ;
for ( let field in send ) {
if ( ! send [ field ] ) {
window . notifications . customError ( "addUserBlankField" , window . lang . notif ( "errorBlankFields" ) ) ;
return ;
}
}
toggleLoader ( button ) ;
_post ( "/users" , send , ( req : XMLHttpRequest ) = > {
if ( req . readyState == 4 ) {
toggleLoader ( button ) ;
if ( req . status == 200 || ( req . response [ "user" ] as boolean ) ) {
window . notifications . customSuccess ( "addUser" , window . lang . var ( "notifications" , "userCreated" , ` " ${ send [ 'username' ] } " ` ) ) ;
if ( ! req . response [ "email" ] ) {
window . notifications . customError ( "sendWelcome" , window . lang . notif ( "errorSendWelcomeEmail" ) ) ;
console . log ( "User created, but welcome email failed" ) ;
}
} else {
window . notifications . customError ( "addUser" , window . lang . var ( "notifications" , "errorUserCreated" , ` " ${ send [ 'username' ] } " ` ) ) ;
}
if ( req . response [ "error" ] as String ) {
console . log ( req . response [ "error" ] ) ;
}
this . reload ( ) ;
window . modals . addUser . close ( ) ;
}
} , true ) ;
}
loadPreview = ( ) = > {
let content = this . _announceTextarea . value ;
if ( ! this . _previewLoaded ) {
content = stripMarkdown ( content ) ;
this . _announcePreview . textContent = content ;
} else {
content = Marked . parse ( content ) ;
this . _announcePreview . innerHTML = content ;
}
}
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 ;
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 ) ;
let send = {
"users" : list ,
"subject" : subject . value ,
"message" : this . _announceTextarea . value
}
_post ( "/users/announce" , send , ( req : XMLHttpRequest ) = > {
if ( req . readyState == 4 ) {
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 ( "sentAnnouncement" ) ) ;
}
}
} ) ;
} ;
_get ( "/config/emails/Announcement" , null , ( req : XMLHttpRequest ) = > {
if ( req . readyState == 4 ) {
const preview = document . getElementById ( "announce-preview" ) as HTMLDivElement ;
if ( req . status != 200 ) {
preview . innerHTML = ` <pre class="preview-content" class="monospace"></pre> ` ;
window . modals . announce . show ( ) ;
this . _previewLoaded = false ;
return ;
}
let templ = req . response as templateEmail ;
if ( ! templ . html ) {
preview . innerHTML = ` <pre class="preview-content" class="monospace"></pre> ` ;
this . _previewLoaded = false ;
} else {
preview . innerHTML = templ . html ;
this . _previewLoaded = true ;
}
this . _announcePreview = preview . getElementsByClassName ( "preview-content" ) [ 0 ] as HTMLElement ;
this . loadPreview ( ) ;
window . modals . announce . show ( ) ;
}
} ) ;
}
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" > & times ; < / 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" ) ;
const form = document . getElementById ( "form-delete-user" ) as HTMLFormElement ;
const button = form . querySelector ( "span.submit" ) as HTMLSpanElement ;
let list = this . _collectUsers ( ) ;
if ( this . _shouldEnable ) {
modalHeader . textContent = window . lang . quantity ( "reEnableUsers" , list . length ) ;
button . textContent = window . lang . strings ( "reEnable" ) ;
button . classList . add ( "~urge" ) ;
button . classList . remove ( "~critical" ) ;
} else {
modalHeader . textContent = window . lang . quantity ( "disableUsers" , list . length ) ;
button . textContent = window . lang . strings ( "disable" ) ;
button . classList . add ( "~critical" ) ;
button . classList . remove ( "~urge" ) ;
}
this . _deleteNotify . checked = false ;
this . _deleteReason . value = "" ;
this . _deleteReason . classList . add ( "unfocused" ) ;
form . onsubmit = ( event : Event ) = > {
event . preventDefault ( ) ;
toggleLoader ( button ) ;
let send = {
"users" : list ,
"enabled" : this . _shouldEnable ,
"notify" : this . _deleteNotify . checked ,
"reason" : this . _deleteNotify ? this . _deleteReason . value : ""
} ;
_post ( "/users/enable" , send , ( req : XMLHttpRequest ) = > {
if ( req . readyState == 4 ) {
toggleLoader ( button ) ;
window . modals . deleteUser . close ( ) ;
if ( req . status != 200 && req . status != 204 ) {
let errorMsg = window . lang . notif ( "errorFailureCheckLogs" ) ;
if ( ! ( "error" in req . response ) ) {
errorMsg = window . lang . notif ( "errorPartialFailureCheckLogs" ) ;
}
window . notifications . customError ( "deleteUserError" , errorMsg ) ;
} else if ( this . _shouldEnable ) {
window . notifications . customSuccess ( "enableUserSuccess" , window . lang . quantity ( "enabledUser" , list . length ) ) ;
} else {
window . notifications . customSuccess ( "disableUserSuccess" , window . lang . quantity ( "disabledUser" , list . length ) ) ;
}
this . reload ( ) ;
}
} , true ) ;
}
window . modals . deleteUser . show ( ) ;
}
deleteUsers = ( ) = > {
const modalHeader = document . getElementById ( "header-delete-user" ) ;
let list = this . _collectUsers ( ) ;
modalHeader . textContent = window . lang . quantity ( "deleteNUsers" , list . length ) ;
const form = document . getElementById ( "form-delete-user" ) as HTMLFormElement ;
const button = form . querySelector ( "span.submit" ) as HTMLSpanElement ;
button . textContent = window . lang . strings ( "delete" ) ;
button . classList . add ( "~critical" ) ;
button . classList . remove ( "~urge" ) ;
this . _deleteNotify . checked = false ;
this . _deleteReason . value = "" ;
this . _deleteReason . classList . add ( "unfocused" ) ;
form . onsubmit = ( event : Event ) = > {
event . preventDefault ( ) ;
toggleLoader ( button ) ;
let send = {
"users" : list ,
"notify" : this . _deleteNotify . checked ,
"reason" : this . _deleteNotify ? this . _deleteReason . value : ""
} ;
_delete ( "/users" , send , ( req : XMLHttpRequest ) = > {
if ( req . readyState == 4 ) {
toggleLoader ( button ) ;
window . modals . deleteUser . close ( ) ;
if ( req . status != 200 && req . status != 204 ) {
let errorMsg = window . lang . notif ( "errorFailureCheckLogs" ) ;
if ( ! ( "error" in req . response ) ) {
errorMsg = window . lang . notif ( "errorPartialFailureCheckLogs" ) ;
}
window . notifications . customError ( "deleteUserError" , errorMsg ) ;
} else {
window . notifications . customSuccess ( "deleteUserSuccess" , window . lang . quantity ( "deletedUser" , list . length ) ) ;
}
this . reload ( ) ;
}
} ) ;
} ;
window . modals . deleteUser . show ( ) ;
}
modifyUsers = ( ) = > {
const modalHeader = document . getElementById ( "header-modify-user" ) ;
modalHeader . textContent = window . lang . quantity ( "modifySettingsFor" , this . _collectUsers ( ) . length )
let list = this . _collectUsers ( ) ;
( ( ) = > {
let innerHTML = "" ;
for ( const profile of window . availableProfiles ) {
innerHTML += ` <option value=" ${ profile } "> ${ profile } </option> ` ;
}
this . _profileSelect . innerHTML = innerHTML ;
} ) ( ) ;
( ( ) = > {
let innerHTML = "" ;
for ( let id in this . _users ) {
innerHTML += ` <option value=" ${ id } "> ${ this . _users [ id ] . name } </option> ` ;
}
this . _userSelect . innerHTML = innerHTML ;
} ) ( ) ;
const form = document . getElementById ( "form-modify-user" ) as HTMLFormElement ;
const button = form . querySelector ( "span.submit" ) as HTMLSpanElement ;
this . _modifySettingsProfile . checked = true ;
this . _modifySettingsUser . checked = false ;
form . onsubmit = ( event : Event ) = > {
event . preventDefault ( ) ;
toggleLoader ( button ) ;
let send = {
"apply_to" : list ,
"homescreen" : ( document . getElementById ( "modify-user-homescreen" ) as HTMLInputElement ) . checked
} ;
if ( this . _modifySettingsProfile . checked && ! this . _modifySettingsUser . checked ) {
send [ "from" ] = "profile" ;
send [ "profile" ] = this . _profileSelect . value ;
} else if ( this . _modifySettingsUser . checked && ! this . _modifySettingsProfile . checked ) {
send [ "from" ] = "user" ;
send [ "id" ] = this . _userSelect . value ;
}
_post ( "/users/settings" , send , ( req : XMLHttpRequest ) = > {
if ( req . readyState == 4 ) {
toggleLoader ( button ) ;
if ( req . status == 500 ) {
let response = JSON . parse ( req . response ) ;
let errorMsg = "" ;
if ( "homescreen" in response && "policy" in response ) {
const homescreen = Object . keys ( response [ "homescreen" ] ) . length ;
const policy = Object . keys ( response [ "policy" ] ) . length ;
if ( homescreen != 0 && policy == 0 ) {
errorMsg = window . lang . notif ( "errorSettingsAppliedNoHomescreenLayout" ) ;
} else if ( policy != 0 && homescreen == 0 ) {
errorMsg = window . lang . notif ( "errorHomescreenAppliedNoSettings" ) ;
} else if ( policy != 0 && homescreen != 0 ) {
errorMsg = window . lang . notif ( "errorSettingsFailed" ) ;
}
} else if ( "error" in response ) {
errorMsg = response [ "error" ] ;
}
window . notifications . customError ( "modifySettingsError" , errorMsg ) ;
} else if ( req . status == 200 || req . status == 204 ) {
window . notifications . customSuccess ( "modifySettingsSuccess" , window . lang . quantity ( "appliedSettings" , this . _collectUsers ( ) . length ) ) ;
}
this . reload ( ) ;
window . modals . modifyUser . close ( ) ;
}
} ) ;
} ;
window . modals . modifyUser . show ( ) ;
}
extendExpiry = ( ) = > {
const list = this . _collectUsers ( ) ;
let applyList : string [ ] = [ ] ;
for ( let id of list ) {
if ( this . _users [ id ] . expiry ) {
applyList . push ( id ) ;
}
}
document . getElementById ( "header-extend-expiry" ) . textContent = window . lang . quantity ( "extendExpiry" , applyList . length ) ;
const form = document . getElementById ( "form-extend-expiry" ) as HTMLFormElement ;
form . onsubmit = ( event : Event ) = > {
event . preventDefault ( ) ;
let send = { "users" : applyList }
for ( let field of [ "months" , "days" , "hours" , "minutes" ] ) {
send [ field ] = + ( document . getElementById ( "extend-expiry-" + field ) as HTMLSelectElement ) . value ;
}
_post ( "/users/extend" , send , ( req : XMLHttpRequest ) = > {
if ( req . readyState == 4 ) {
if ( req . status != 200 && req . status != 204 ) {
window . notifications . customError ( "extendExpiryError" , window . lang . notif ( "errorFailureCheckLogs" ) ) ;
} else {
window . notifications . customSuccess ( "extendExpiry" , window . lang . quantity ( "extendedExpiry" , applyList . length ) ) ;
}
window . modals . extendExpiry . close ( )
this . reload ( ) ;
}
} ) ;
}
window . modals . extendExpiry . show ( ) ;
}
constructor ( ) {
this . _populateNumbers ( ) ;
this . _users = { } ;
this . _selectAll . checked = false ;
this . _selectAll . onchange = ( ) = > {
this . selectAll = this . _selectAll . checked ;
} ;
document . addEventListener ( "accounts-reload" , this . reload ) ;
document . addEventListener ( "accountCheckEvent" , ( ) = > { this . _checkCount ++ ; this . _checkCheckCount ( ) ; } ) ;
document . addEventListener ( "accountUncheckEvent" , ( ) = > { this . _checkCount -- ; this . _checkCheckCount ( ) ; } ) ;
this . _addUserButton . onclick = window . modals . addUser . toggle ;
this . _addUserForm . addEventListener ( "submit" , this . _addUser ) ;
this . _deleteNotify . onchange = ( ) = > {
if ( this . _deleteNotify . checked ) {
this . _deleteReason . classList . remove ( "unfocused" ) ;
} else {
this . _deleteReason . classList . add ( "unfocused" ) ;
}
} ;
this . _modifySettings . onclick = this . modifyUsers ;
this . _modifySettings . classList . add ( "unfocused" ) ;
const checkSource = ( ) = > {
const profileSpan = this . _modifySettingsProfile . nextElementSibling as HTMLSpanElement ;
const userSpan = this . _modifySettingsUser . nextElementSibling as HTMLSpanElement ;
if ( this . _modifySettingsProfile . checked ) {
this . _userSelect . parentElement . classList . add ( "unfocused" ) ;
this . _profileSelect . parentElement . classList . remove ( "unfocused" )
profileSpan . classList . add ( "!high" ) ;
profileSpan . classList . remove ( "!normal" ) ;
userSpan . classList . remove ( "!high" ) ;
userSpan . classList . add ( "!normal" ) ;
} else {
this . _userSelect . parentElement . classList . remove ( "unfocused" ) ;
this . _profileSelect . parentElement . classList . add ( "unfocused" ) ;
userSpan . classList . add ( "!high" ) ;
userSpan . classList . remove ( "!normal" ) ;
profileSpan . classList . remove ( "!high" ) ;
profileSpan . classList . add ( "!normal" ) ;
}
} ;
this . _modifySettingsProfile . onchange = checkSource ;
this . _modifySettingsUser . onchange = checkSource ;
this . _deleteUser . onclick = this . deleteUsers ;
this . _deleteUser . classList . add ( "unfocused" ) ;
this . _announceButton . onclick = this . announce ;
this . _announceButton . classList . add ( "unfocused" ) ;
this . _extendExpiry . onclick = this . extendExpiry ;
this . _extendExpiry . classList . add ( "unfocused" ) ;
this . _disableEnable . onclick = this . enableDisableUsers ;
this . _disableEnable . classList . add ( "unfocused" ) ;
if ( ! window . usernameEnabled ) {
this . _addUserName . classList . add ( "unfocused" ) ;
this . _addUserName = this . _addUserEmail ;
}
/ * i f ( ! w i n d o w . e m a i l E n a b l e d ) {
this . _deleteNotify . parentElement . classList . add ( "unfocused" ) ;
this . _deleteNotify . checked = false ;
} * /
const setVisibility = ( users : string [ ] , visible : boolean ) = > {
for ( let id in this . _users ) {
if ( users . indexOf ( id ) != - 1 ) {
if ( visible ) {
this . unhide ( id ) ;
} else {
this . hide ( id ) ;
}
} else {
if ( visible ) {
this . hide ( id ) ;
} else {
this . unhide ( id ) ;
}
}
}
}
this . _search . oninput = ( ) = > {
const query = this . _search . value ;
if ( ! query ) {
setVisibility ( Object . keys ( this . _users ) , true ) ;
this . _inSearch = false ;
} else {
this . _inSearch = true ;
setVisibility ( this . search ( query ) , true ) ;
}
this . _checkCheckCount ( ) ;
} ;
this . _announceTextarea . onkeyup = this . loadPreview ;
addDiscord = newDiscordSearch ( window . lang . strings ( "linkDiscord" ) , window . lang . strings ( "searchDiscordUser" ) , window . lang . strings ( "add" ) , ( user : DiscordUser , id : string ) = > {
_post ( "/users/discord" , { jf_id : id , discord_id : user.id } , ( req : XMLHttpRequest ) = > {
if ( req . readyState == 4 ) {
document . dispatchEvent ( new CustomEvent ( "accounts-reload" ) ) ;
if ( req . status != 200 ) {
window . notifications . customError ( "errorConnectDiscord" , window . lang . notif ( "errorFailureCheckLogs" ) ) ;
return
}
window . notifications . customSuccess ( "discordConnected" , window . lang . notif ( "accountConnected" ) ) ;
window . modals . discord . close ( )
}
} ) ;
} ) ;
this . _announceSaveButton . onclick = this . saveAnnouncement ;
const announceVarUsername = document . getElementById ( "announce-variables-username" ) as HTMLSpanElement ;
announceVarUsername . onclick = ( ) = > {
insertText ( this . _announceTextarea , announceVarUsername . children [ 0 ] . textContent ) ;
this . loadPreview ( ) ;
} ;
}
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 ( ) ;
}
} ) ;
this . loadTemplates ( ) ;
}
}