mirror of
https://github.com/Terncode/pixel.horse.git
synced 2026-09-24 13:55:04 +02:00
293 lines
9.7 KiB
TypeScript
293 lines
9.7 KiB
TypeScript
import { Component, Input, OnChanges, SimpleChanges, OnInit, TemplateRef, ViewChild } from '@angular/core';
|
|
import { BsModalService, BsModalRef } from 'ngx-bootstrap/modal';
|
|
import { compact } from 'lodash';
|
|
import { DAY, MINUTE, HOUR } from '../../../../common/constants';
|
|
import { hasFlag, fromNow, toInt, setFlag } from '../../../../common/utils';
|
|
import {
|
|
Account, AccountFlags, accountCounters, accountFlags, SupporterFlags, supporterFlags, BannedMuted, DuplicatesInfo
|
|
} from '../../../../common/adminInterfaces';
|
|
import { supporterLevel, patreonSupporterLevel, getAge, isPastSupporter } from '../../../../common/adminUtils';
|
|
import { AdminModel } from '../../../services/adminModel';
|
|
import { AccountCounters } from '../../../../common/interfaces';
|
|
import {
|
|
faPatreon, faCog, faMinus, faPlus, faCheck, faFlag, faStickyNote, faCertificate, faIdBadge, faEnvelope, faFont,
|
|
faClock, faBan, faMapMarkerAlt
|
|
} from '../../../../client/icons';
|
|
|
|
const EMPTY_ROLES: string[] = [];
|
|
const oldTime = fromNow(-14 * DAY).getTime();
|
|
const newTime = fromNow(-DAY).getTime();
|
|
|
|
const accountDuplicatesIntervalTime = 10 * MINUTE;
|
|
const accountDuplicates = new Map<string, DuplicatesInfo>();
|
|
|
|
const predefinedAlerts = [
|
|
{
|
|
name: 'erp:flagged',
|
|
message: `Your account has been flagged for inappropriate behavior on a PG rated server. `
|
|
+ `Continuing that behavior may result in a permanent ban.`
|
|
},
|
|
{
|
|
name: 'erp:timeout',
|
|
message: `Your account has been timed out for inappropriate language and behavior on a PG rated server. `
|
|
+ `Continuing that behavior may result in a permanent ban.`
|
|
},
|
|
{
|
|
name: 'dups',
|
|
message: `Your account has been flagged for making multiple accounts. `
|
|
+ `Continuing that behavior may result in a permanent ban.`
|
|
},
|
|
{
|
|
name: 'under',
|
|
message: `Your account has been reported for being underage, please do NOT play on an 18+ server. `
|
|
+ `Continuing that may result in a permanent ban.`
|
|
},
|
|
];
|
|
|
|
const alertExpires = [
|
|
{ name: '1h', length: HOUR },
|
|
{ name: '5h', length: 5 * HOUR },
|
|
{ name: '12h', length: 12 * HOUR },
|
|
{ name: '1d', length: DAY },
|
|
{ name: '2d', length: 2 * DAY },
|
|
{ name: '5d', length: 5 * DAY },
|
|
{ name: '7d', length: 7 * DAY },
|
|
{ name: '2w', length: 14 * DAY },
|
|
];
|
|
|
|
@Component({
|
|
selector: 'account-info',
|
|
templateUrl: 'account-info.pug',
|
|
styleUrls: ['account-info.scss'],
|
|
})
|
|
export class AccountInfo implements OnInit, OnChanges {
|
|
readonly counters = accountCounters;
|
|
readonly flags = accountFlags;
|
|
readonly supporterFlags = supporterFlags;
|
|
readonly cogIcon = faCog;
|
|
readonly minusIcon = faMinus;
|
|
readonly plusIcon = faPlus;
|
|
readonly checkIcon = faCheck;
|
|
readonly flagIcon = faFlag;
|
|
readonly noteIcon = faStickyNote;
|
|
readonly newIcon = faCertificate;
|
|
readonly duplicateBrowserIdIcon = faIdBadge;
|
|
readonly duplicateEmailIcon = faEnvelope;
|
|
readonly duplicateNameIcon = faFont;
|
|
readonly duplicatePermaIcon = faBan;
|
|
readonly teleportIcon = faMapMarkerAlt;
|
|
predefinedAlerts = predefinedAlerts;
|
|
alertExpires = alertExpires;
|
|
alertExpire = alertExpires[3];
|
|
alertMessage = '';
|
|
@Input() account!: Account;
|
|
@Input() extendedAuths = false;
|
|
@Input() popoverPlacement?: string;
|
|
@Input() showDuplicates = false;
|
|
@ViewChild('alertModal', { static: true }) alertModal!: TemplateRef<any>;
|
|
note?: string;
|
|
duplicates?: DuplicatesInfo;
|
|
private alertModalRef?: BsModalRef;
|
|
private _isNoteOpen = false;
|
|
constructor(private model: AdminModel, private modalService: BsModalService) {
|
|
}
|
|
ngOnInit() {
|
|
this.updateDuplicates();
|
|
}
|
|
ngOnChanges(changes: SimpleChanges) {
|
|
if (changes.account) {
|
|
this.updateDuplicates();
|
|
}
|
|
}
|
|
get age() {
|
|
return this.account.birthdate ? getAge(this.account.birthdate) : '-';
|
|
}
|
|
get alert() {
|
|
const alert = this.account.alert;
|
|
return (alert && alert.expires.getTime() > Date.now()) ? alert : undefined;
|
|
}
|
|
get isNew() {
|
|
return this.account.createdAt && this.account.createdAt.getTime() > newTime;
|
|
}
|
|
get isNoteOpen() {
|
|
return this._isNoteOpen;
|
|
}
|
|
set isNoteOpen(value: boolean) {
|
|
if (this._isNoteOpen !== value) {
|
|
this._isNoteOpen = value;
|
|
|
|
if (value) {
|
|
this.note = this.account.note;
|
|
}
|
|
}
|
|
}
|
|
get isInactive() {
|
|
return this.account && this.account.lastVisit && this.account.lastVisit.getTime() < oldTime;
|
|
}
|
|
get roles() {
|
|
return this.account.roles ? this.account.roles.filter(r => r !== 'superadmin') : EMPTY_ROLES;
|
|
}
|
|
get flagClass() {
|
|
const counters = this.account.counters;
|
|
|
|
if (this.account.flags) {
|
|
return 'text-banned';
|
|
} else if (!counters && !this.account.supporter) {
|
|
return 'text-muted';
|
|
} else if (counters && ((counters.spam || 0) > 100 || (counters.swears || 0) > 10)) {
|
|
return 'text-alert';
|
|
} else {
|
|
return 'text-present';
|
|
}
|
|
}
|
|
get hasDuplicateNote() {
|
|
return this.account.note && /duplicate/i.test(this.account.note);
|
|
}
|
|
hasFlag(value: AccountFlags) {
|
|
return hasFlag(this.account.flags, value);
|
|
}
|
|
toggleFlag(value: AccountFlags) {
|
|
this.model.setAccountFlags(this.account._id, this.account.flags ^ value);
|
|
}
|
|
toggleBan(field: keyof BannedMuted, value: number) {
|
|
this.model.setAccountBanField(this.account._id, field, value);
|
|
}
|
|
kick() {
|
|
this.model.kick(this.account._id);
|
|
}
|
|
report() {
|
|
this.model.report(this.account._id);
|
|
}
|
|
blur() {
|
|
this.model.setNote(this.account._id, this.note || '');
|
|
this.isNoteOpen = false;
|
|
}
|
|
decrementCounter(name: keyof AccountCounters) {
|
|
if (this.getCounter(name) > 0) {
|
|
this.setCounter(name, this.getCounter(name) - 1);
|
|
}
|
|
}
|
|
incrementCounter(name: keyof AccountCounters) {
|
|
this.setCounter(name, this.getCounter(name) + 1);
|
|
}
|
|
getCounter(name: keyof AccountCounters) {
|
|
const counters = this.account.counters;
|
|
return toInt(counters && counters[name]);
|
|
}
|
|
setCounter(name: keyof AccountCounters, value: number) {
|
|
const counters = this.account.counters || (this.account.counters = {});
|
|
counters[name] = value;
|
|
this.model.setAccountCounter(this.account._id, name, value);
|
|
}
|
|
removeAlert() {
|
|
this.model.setAlert(this.account._id, '', 0);
|
|
}
|
|
setAlert() {
|
|
this.alertMessage = this.alert ? this.alert.message : '';
|
|
this.alertExpire = this.alertExpires[2];
|
|
this.alertModalRef = this.modalService.show(this.alertModal, { ignoreBackdropClick: true });
|
|
}
|
|
cancelAlert() {
|
|
this.alertModalRef && this.alertModalRef.hide();
|
|
this.alertModalRef = undefined;
|
|
}
|
|
confirmAlert() {
|
|
this.model.setAlert(this.account._id, this.alertMessage, this.alertExpire.length);
|
|
this.cancelAlert();
|
|
}
|
|
private updateDuplicates() {
|
|
const account = this.account;
|
|
|
|
if (this.showDuplicates && account) {
|
|
const cached = accountDuplicates.get(account._id);
|
|
const threshold = fromNow(-accountDuplicatesIntervalTime);
|
|
|
|
if (cached && cached.generatedAt > threshold.getTime()) {
|
|
this.duplicates = cached;
|
|
} else {
|
|
this.model.getAllDuplicatesQuickInfo(account._id)
|
|
.then(duplicates => {
|
|
if (duplicates) {
|
|
accountDuplicates.set(account._id, duplicates);
|
|
this.duplicates = duplicates;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
teleportTo() {
|
|
this.model.teleportTo(this.account._id);
|
|
}
|
|
// supporters
|
|
get isPatreonOrSupporter() {
|
|
return !!(this.account.patreon || this.account.supporter || this.account.supporterDeclinedSince);
|
|
}
|
|
get supporterClass() {
|
|
return supporterLevel(this.account) ? 'badge-success' : 'badge-warning';
|
|
}
|
|
get supporterTitle() {
|
|
const supporter = this.account.supporter!;
|
|
const flagSupporter = (supporter & SupporterFlags.SupporterMask) !== 0;
|
|
const patreonSupporter = patreonSupporterLevel(this.account);
|
|
const ignorePatreon = hasFlag(supporter, SupporterFlags.IgnorePatreon);
|
|
const pastSupporter = hasFlag(supporter, SupporterFlags.PastSupporter);
|
|
|
|
return compact([
|
|
flagSupporter && 'flags',
|
|
patreonSupporter && `patreon`,
|
|
ignorePatreon && 'ignore',
|
|
!patreonSupporter && this.account.supporterDeclinedSince && 'declined',
|
|
pastSupporter && 'past',
|
|
]).join(', ');
|
|
}
|
|
get supporterIcon() {
|
|
const hasPatreon = patreonSupporterLevel(this.account);
|
|
const hasIgnoreFlag = hasFlag(this.account.supporter, SupporterFlags.IgnorePatreon);
|
|
const hasDeclined = !!this.account.supporterDeclinedSince;
|
|
return hasPatreon ? faPatreon : ((hasIgnoreFlag || !hasDeclined) ? faFlag : faClock);
|
|
}
|
|
get hasAnySupporter() {
|
|
return (this.account.supporter! & SupporterFlags.SupporterMask) !== 0;
|
|
}
|
|
get hasPastSupporter() {
|
|
return hasFlag(this.account.supporter, SupporterFlags.PastSupporter);
|
|
}
|
|
get supporterLevel() {
|
|
return supporterLevel(this.account);
|
|
}
|
|
get supporterLevelString() {
|
|
const level = supporterLevel(this.account);
|
|
return level ? level : (isPastSupporter(this.account) ? 'P' : '');
|
|
}
|
|
isSupporter(level: number) {
|
|
return (this.account.supporter! & SupporterFlags.SupporterMask) === level;
|
|
}
|
|
setSupporter(level: number) {
|
|
const supporter = (this.account.supporter! & ~SupporterFlags.SupporterMask) | level;
|
|
this.model.setSupporterFlags(this.account._id, supporter);
|
|
}
|
|
hasSupporterFlag(value: SupporterFlags) {
|
|
return hasFlag(this.account.supporter, value);
|
|
}
|
|
toggleSupporterFlag(value: SupporterFlags) {
|
|
this.model.setSupporterFlags(this.account._id, this.account.supporter! ^ value);
|
|
}
|
|
// past supporter
|
|
get isForcePastSupporter() {
|
|
return hasFlag(this.account.supporter, SupporterFlags.ForcePastSupporter);
|
|
}
|
|
get isIgnorePastSupporter() {
|
|
return hasFlag(this.account.supporter, SupporterFlags.IgnorePastSupporter);
|
|
}
|
|
toggleForcePastSupporter() {
|
|
const has = hasFlag(this.account.supporter, SupporterFlags.ForcePastSupporter);
|
|
const supporter = setFlag(this.account.supporter, SupporterFlags.ForcePastSupporter, !has);
|
|
this.model.setSupporterFlags(this.account._id, supporter);
|
|
}
|
|
toggleIgnorePastSupporter() {
|
|
const has = hasFlag(this.account.supporter, SupporterFlags.IgnorePastSupporter);
|
|
const supporter = setFlag(this.account.supporter, SupporterFlags.IgnorePastSupporter, !has);
|
|
this.model.setSupporterFlags(this.account._id, supporter);
|
|
}
|
|
}
|