diff --git a/client/src/app/+admin/moderation/abuse-list/abuse-list.component.html b/client/src/app/+admin/moderation/abuse-list/abuse-list.component.html
index 48b31b99c..9fae5667f 100644
--- a/client/src/app/+admin/moderation/abuse-list/abuse-list.component.html
+++ b/client/src/app/+admin/moderation/abuse-list/abuse-list.component.html
@@ -46,6 +46,7 @@
Video/Comment/Account |
Created |
State |
+ Messages |
|
@@ -157,6 +158,12 @@
+
+ {{ abuse.countMessages }}
+
+
+ |
+
+
diff --git a/client/src/app/+admin/moderation/abuse-list/abuse-list.component.scss b/client/src/app/+admin/moderation/abuse-list/abuse-list.component.scss
index c22f98c47..48536e3c2 100644
--- a/client/src/app/+admin/moderation/abuse-list/abuse-list.component.scss
+++ b/client/src/app/+admin/moderation/abuse-list/abuse-list.component.scss
@@ -21,3 +21,12 @@
margin-left: 0;
}
}
+
+.abuse-messages {
+ my-global-icon {
+ width: 22px;
+ margin-left: 3px;
+ position: relative;
+ top: -2px;
+ }
+}
diff --git a/client/src/app/+admin/moderation/abuse-list/abuse-list.component.ts b/client/src/app/+admin/moderation/abuse-list/abuse-list.component.ts
index 74c5fe2b3..86121fe58 100644
--- a/client/src/app/+admin/moderation/abuse-list/abuse-list.component.ts
+++ b/client/src/app/+admin/moderation/abuse-list/abuse-list.component.ts
@@ -8,17 +8,17 @@ import { DomSanitizer, SafeHtml } from '@angular/platform-browser'
import { ActivatedRoute, Params, Router } from '@angular/router'
import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable } from '@app/core'
import { Account, Actor, DropdownAction, Video, VideoService } from '@app/shared/shared-main'
-import { AbuseService, BlocklistService, VideoBlockService } from '@app/shared/shared-moderation'
+import { AbuseService, BlocklistService, VideoBlockService, AbuseMessageModalComponent } from '@app/shared/shared-moderation'
import { VideoCommentService } from '@app/shared/shared-video-comment'
import { I18n } from '@ngx-translate/i18n-polyfill'
-import { Abuse, AbuseState } from '@shared/models'
+import { AdminAbuse, AbuseState } from '@shared/models'
import { ModerationCommentModalComponent } from './moderation-comment-modal.component'
const logger = debug('peertube:moderation:AbuseListComponent')
// Don't use an abuse model because we need external services to compute some properties
// And this model is only used in this component
-export type ProcessedAbuse = Abuse & {
+export type ProcessedAbuse = AdminAbuse & {
moderationCommentHtml?: string,
reasonHtml?: string
embedHtml?: SafeHtml
@@ -31,8 +31,8 @@ export type ProcessedAbuse = Abuse & {
truncatedCommentHtml?: string
commentHtml?: string
- video: Abuse['video'] & {
- channel: Abuse['video']['channel'] & {
+ video: AdminAbuse['video'] & {
+ channel: AdminAbuse['video']['channel'] & {
ownerAccount: Account
}
}
@@ -45,6 +45,7 @@ export type ProcessedAbuse = Abuse & {
})
export class AbuseListComponent extends RestTable implements OnInit, AfterViewInit {
@ViewChild('moderationCommentModal', { static: true }) moderationCommentModal: ModerationCommentModalComponent
+ @ViewChild('abuseMessagesModal', { static: true }) abuseMessagesModal: AbuseMessageModalComponent
abuses: ProcessedAbuse[] = []
totalRecords = 0
@@ -104,7 +105,7 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn
return 'AbuseListComponent'
}
- openModerationCommentModal (abuse: Abuse) {
+ openModerationCommentModal (abuse: AdminAbuse) {
this.moderationCommentModal.openModal(abuse)
}
@@ -132,19 +133,19 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn
}
/* END Table filter functions */
- isAbuseAccepted (abuse: Abuse) {
+ isAbuseAccepted (abuse: AdminAbuse) {
return abuse.state.id === AbuseState.ACCEPTED
}
- isAbuseRejected (abuse: Abuse) {
+ isAbuseRejected (abuse: AdminAbuse) {
return abuse.state.id === AbuseState.REJECTED
}
- getVideoUrl (abuse: Abuse) {
+ getVideoUrl (abuse: AdminAbuse) {
return Video.buildClientUrl(abuse.video.uuid)
}
- getCommentUrl (abuse: Abuse) {
+ getCommentUrl (abuse: AdminAbuse) {
return Video.buildClientUrl(abuse.comment.video.uuid) + ';threadId=' + abuse.comment.threadId
}
@@ -152,7 +153,7 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn
return '/accounts/' + abuse.flaggedAccount.nameWithHost
}
- getVideoEmbed (abuse: Abuse) {
+ getVideoEmbed (abuse: AdminAbuse) {
return buildVideoEmbed(
buildVideoLink({
baseUrl: `${environment.embedUrl}/videos/embed/${abuse.video.uuid}`,
@@ -168,7 +169,7 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn
($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL()
}
- async removeAbuse (abuse: Abuse) {
+ async removeAbuse (abuse: AdminAbuse) {
const res = await this.confirmService.confirm(this.i18n('Do you really want to delete this abuse report?'), this.i18n('Delete'))
if (res === false) return
@@ -182,7 +183,7 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn
)
}
- updateAbuseState (abuse: Abuse, state: AbuseState) {
+ updateAbuseState (abuse: AdminAbuse, state: AbuseState) {
this.abuseService.updateAbuse(abuse, { state })
.subscribe(
() => this.loadData(),
@@ -191,10 +192,25 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn
)
}
+ onCountMessagesUpdated (event: { abuseId: number, countMessages: number }) {
+ const abuse = this.abuses.find(a => a.id === event.abuseId)
+
+ if (!abuse) {
+ console.error('Cannot find abuse %d.', event.abuseId)
+ return
+ }
+
+ abuse.countMessages = event.countMessages
+ }
+
+ openAbuseMessagesModal (abuse: AdminAbuse) {
+ this.abuseMessagesModal.openModal(abuse)
+ }
+
protected loadData () {
logger('Load data.')
- return this.abuseService.getAbuses({
+ return this.abuseService.getAdminAbuses({
pagination: this.pagination,
sort: this.sort,
search: this.search
@@ -257,7 +273,11 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn
handler: abuse => this.removeAbuse(abuse)
},
{
- label: this.i18n('Add note'),
+ label: this.i18n('Messages'),
+ handler: abuse => this.openAbuseMessagesModal(abuse)
+ },
+ {
+ label: this.i18n('Add internal note'),
handler: abuse => this.openModerationCommentModal(abuse),
isDisplayed: abuse => !abuse.moderationComment
},
diff --git a/client/src/app/+admin/moderation/abuse-list/moderation-comment-modal.component.ts b/client/src/app/+admin/moderation/abuse-list/moderation-comment-modal.component.ts
index 23738f9cd..ecb7966bf 100644
--- a/client/src/app/+admin/moderation/abuse-list/moderation-comment-modal.component.ts
+++ b/client/src/app/+admin/moderation/abuse-list/moderation-comment-modal.component.ts
@@ -5,7 +5,7 @@ import { AbuseService } from '@app/shared/shared-moderation'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
import { I18n } from '@ngx-translate/i18n-polyfill'
-import { Abuse } from '@shared/models'
+import { AdminAbuse } from '@shared/models'
@Component({
selector: 'my-moderation-comment-modal',
@@ -16,7 +16,7 @@ export class ModerationCommentModalComponent extends FormReactive implements OnI
@ViewChild('modal', { static: true }) modal: NgbModal
@Output() commentUpdated = new EventEmitter()
- private abuseToComment: Abuse
+ private abuseToComment: AdminAbuse
private openedModal: NgbModalRef
constructor (
@@ -36,7 +36,7 @@ export class ModerationCommentModalComponent extends FormReactive implements OnI
})
}
- openModal (abuseToComment: Abuse) {
+ openModal (abuseToComment: AdminAbuse) {
this.abuseToComment = abuseToComment
this.openedModal = this.modalService.open(this.modal, { centered: true })
diff --git a/client/src/app/shared/shared-forms/form-validators/abuse-validators.service.ts b/client/src/app/shared/shared-forms/form-validators/abuse-validators.service.ts
index 739115e19..5f15963f3 100644
--- a/client/src/app/shared/shared-forms/form-validators/abuse-validators.service.ts
+++ b/client/src/app/shared/shared-forms/form-validators/abuse-validators.service.ts
@@ -7,6 +7,7 @@ import { BuildFormValidator } from './form-validator.service'
export class AbuseValidatorsService {
readonly ABUSE_REASON: BuildFormValidator
readonly ABUSE_MODERATION_COMMENT: BuildFormValidator
+ readonly ABUSE_MESSAGE: BuildFormValidator
constructor (private i18n: I18n) {
this.ABUSE_REASON = {
@@ -26,5 +27,14 @@ export class AbuseValidatorsService {
'maxlength': this.i18n('Moderation comment cannot be more than 3000 characters long.')
}
}
+
+ this.ABUSE_MESSAGE = {
+ VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(3000) ],
+ MESSAGES: {
+ 'required': this.i18n('Abuse message is required.'),
+ 'minlength': this.i18n('Abuse message must be at least 2 characters long.'),
+ 'maxlength': this.i18n('Abuse message cannot be more than 3000 characters long.')
+ }
+ }
}
}
diff --git a/client/src/app/shared/shared-icons/global-icon.component.ts b/client/src/app/shared/shared-icons/global-icon.component.ts
index c58ef29fa..409681702 100644
--- a/client/src/app/shared/shared-icons/global-icon.component.ts
+++ b/client/src/app/shared/shared-icons/global-icon.component.ts
@@ -64,8 +64,7 @@ const icons = {
'go': require('!!raw-loader?!../../../assets/images/feather/arrow-up-right.svg').default,
'cross': require('!!raw-loader?!../../../assets/images/feather/x.svg').default,
'tick': require('!!raw-loader?!../../../assets/images/feather/check.svg').default,
- 'repeat': require('!!raw-loader?!../../../assets/images/feather/repeat.svg').default,
- 'columns': require('!!raw-loader?!../../../assets/images/feather/columns.svg').default
+ 'message-circle': require('!!raw-loader?!../../../assets/images/feather/message-circle.svg').default
}
export type GlobalIconName = keyof typeof icons
diff --git a/client/src/app/shared/shared-moderation/abuse-message-modal.component.html b/client/src/app/shared/shared-moderation/abuse-message-modal.component.html
new file mode 100644
index 000000000..67c6a3081
--- /dev/null
+++ b/client/src/app/shared/shared-moderation/abuse-message-modal.component.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ {{ message.account.name }}
+
+
+ {{ message.message }}
+ {{ message.createdAt | date }}
+
+
+
+
+
+
+
+
+
diff --git a/client/src/app/shared/shared-moderation/abuse-message-modal.component.scss b/client/src/app/shared/shared-moderation/abuse-message-modal.component.scss
new file mode 100644
index 000000000..89d6b88c1
--- /dev/null
+++ b/client/src/app/shared/shared-moderation/abuse-message-modal.component.scss
@@ -0,0 +1,57 @@
+@import 'variables';
+@import 'mixins';
+
+form {
+ margin: 20px 20px 0 0;
+}
+
+textarea {
+ @include peertube-textarea(100%, 70px);
+
+ margin-top: 20px;
+}
+
+.messages {
+ display: flex;
+ flex-direction: column;
+ overflow-y: scroll;
+ margin-right: 5px;
+}
+
+.message-block {
+ margin-bottom: 10px;
+ max-width: 60%;
+
+ .author {
+ color: var(--greyForegroundColor);
+ font-size: 14px;
+ }
+
+ .bubble {
+ color: var(--mainForegroundColor);
+ background-color: var(--greyBackgroundColor);
+ border-radius: 10px;
+ padding: 5px 10px;
+
+ &.by-me {
+ color: var(--mainForegroundColor);
+ background-color: var(--secondaryColor);
+ }
+
+ &.by-moderator {
+ color: #fff;
+ background-color: var(--mainColor);
+
+ align-self: flex-end;
+ }
+
+ .content {
+ font-size: 15px;
+ }
+
+ .date {
+ font-size: 13px;
+ color: var(--greyForegroundColor);
+ }
+ }
+}
diff --git a/client/src/app/shared/shared-moderation/abuse-message-modal.component.ts b/client/src/app/shared/shared-moderation/abuse-message-modal.component.ts
new file mode 100644
index 000000000..5822dfe1d
--- /dev/null
+++ b/client/src/app/shared/shared-moderation/abuse-message-modal.component.ts
@@ -0,0 +1,115 @@
+import { Component, ElementRef, EventEmitter, Output, ViewChild, OnInit } from '@angular/core'
+import { Notifier, AuthService } from '@app/core'
+import { FormReactive, FormValidatorService, AbuseValidatorsService } from '@app/shared/shared-forms'
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
+import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
+import { I18n } from '@ngx-translate/i18n-polyfill'
+import { AbuseMessage, UserAbuse } from '@shared/models'
+import { AbuseService } from './abuse.service'
+
+@Component({
+ selector: 'my-abuse-message-modal',
+ templateUrl: './abuse-message-modal.component.html',
+ styleUrls: [ './abuse-message-modal.component.scss' ]
+})
+export class AbuseMessageModalComponent extends FormReactive implements OnInit {
+ @ViewChild('modal', { static: true }) modal: NgbModal
+ @ViewChild('messagesBlock', { static: false }) messagesBlock: ElementRef
+
+ @Output() countMessagesUpdated = new EventEmitter<{ abuseId: number, countMessages: number }>()
+
+ abuseMessages: AbuseMessage[] = []
+ textareaMessage: string
+ sendingMessage = false
+
+ private openedModal: NgbModalRef
+ private abuse: UserAbuse
+
+ constructor (
+ protected formValidatorService: FormValidatorService,
+ private abuseValidatorsService: AbuseValidatorsService,
+ private modalService: NgbModal,
+ private auth: AuthService,
+ private notifier: Notifier,
+ private i18n: I18n,
+ private abuseService: AbuseService
+ ) {
+ super()
+ }
+
+ ngOnInit () {
+ this.buildForm({
+ message: this.abuseValidatorsService.ABUSE_MESSAGE
+ })
+ }
+
+ openModal (abuse: UserAbuse) {
+ this.abuse = abuse
+
+ this.openedModal = this.modalService.open(this.modal, { centered: true })
+
+ this.loadMessages()
+ }
+
+ hide () {
+ this.abuseMessages = []
+ this.openedModal.close()
+ }
+
+ addMessage () {
+ this.sendingMessage = true
+
+ this.abuseService.addAbuseMessage(this.abuse, this.form.value['message'])
+ .subscribe(
+ () => {
+ this.form.reset()
+ this.sendingMessage = false
+ this.countMessagesUpdated.emit({ abuseId: this.abuse.id, countMessages: this.abuseMessages.length + 1 })
+
+ this.loadMessages()
+ },
+
+ err => {
+ this.sendingMessage = false
+ console.error(err)
+ this.notifier.error('Sorry but you cannot send this message. Please retry later')
+ }
+ )
+ }
+
+ deleteMessage (abuseMessage: AbuseMessage) {
+ this.abuseService.deleteAbuseMessage(this.abuse, abuseMessage)
+ .subscribe(
+ () => {
+ this.countMessagesUpdated.emit({ abuseId: this.abuse.id, countMessages: this.abuseMessages.length - 1 })
+
+ this.abuseMessages = this.abuseMessages.filter(m => m.id !== abuseMessage.id)
+ },
+
+ err => this.notifier.error(err.message)
+ )
+ }
+
+ isMessageByMe (abuseMessage: AbuseMessage) {
+ return this.auth.getUser().account.id === abuseMessage.account.id
+ }
+
+ private loadMessages () {
+ this.abuseService.listAbuseMessages(this.abuse)
+ .subscribe(
+ res => {
+ this.abuseMessages = res.data
+
+ setTimeout(() => {
+ if (!this.messagesBlock) return
+
+ const element = this.messagesBlock.nativeElement as HTMLElement
+ element.scrollIntoView({ block: 'end', inline: 'nearest' })
+ })
+ },
+
+ err => this.notifier.error(err.message)
+ )
+ }
+
+}
diff --git a/client/src/app/shared/shared-moderation/abuse.service.ts b/client/src/app/shared/shared-moderation/abuse.service.ts
index 95ac16955..652d8370f 100644
--- a/client/src/app/shared/shared-moderation/abuse.service.ts
+++ b/client/src/app/shared/shared-moderation/abuse.service.ts
@@ -5,7 +5,7 @@ import { catchError, map } from 'rxjs/operators'
import { HttpClient, HttpParams } from '@angular/common/http'
import { Injectable } from '@angular/core'
import { RestExtractor, RestPagination, RestService } from '@app/core'
-import { Abuse, AbuseCreate, AbuseFilter, AbusePredefinedReasonsString, AbuseState, AbuseUpdate, ResultList } from '@shared/models'
+import { AdminAbuse, AbuseCreate, AbuseFilter, AbusePredefinedReasonsString, AbuseState, AbuseUpdate, ResultList, UserAbuse, AbuseMessage } from '@shared/models'
import { environment } from '../../../environments/environment'
import { I18n } from '@ngx-translate/i18n-polyfill'
@@ -20,11 +20,11 @@ export class AbuseService {
private restExtractor: RestExtractor
) { }
- getAbuses (options: {
+ getAdminAbuses (options: {
pagination: RestPagination,
sort: SortMeta,
search?: string
- }): Observable> {
+ }): Observable> {
const { pagination, sort, search } = options
const url = AbuseService.BASE_ABUSE_URL
@@ -61,7 +61,7 @@ export class AbuseService {
params = this.restService.addObjectParams(params, filters)
}
- return this.authHttp.get>(url, { params })
+ return this.authHttp.get>(url, { params })
.pipe(
catchError(res => this.restExtractor.handleError(res))
)
@@ -79,7 +79,7 @@ export class AbuseService {
)
}
- updateAbuse (abuse: Abuse, abuseUpdate: AbuseUpdate) {
+ updateAbuse (abuse: AdminAbuse, abuseUpdate: AbuseUpdate) {
const url = AbuseService.BASE_ABUSE_URL + '/' + abuse.id
return this.authHttp.put(url, abuseUpdate)
@@ -89,7 +89,7 @@ export class AbuseService {
)
}
- removeAbuse (abuse: Abuse) {
+ removeAbuse (abuse: AdminAbuse) {
const url = AbuseService.BASE_ABUSE_URL + '/' + abuse.id
return this.authHttp.delete(url)
@@ -99,6 +99,35 @@ export class AbuseService {
)
}
+ addAbuseMessage (abuse: UserAbuse, message: string) {
+ const url = AbuseService.BASE_ABUSE_URL + '/' + abuse.id + '/messages'
+
+ return this.authHttp.post(url, { message })
+ .pipe(
+ map(this.restExtractor.extractDataBool),
+ catchError(res => this.restExtractor.handleError(res))
+ )
+ }
+
+ listAbuseMessages (abuse: UserAbuse) {
+ const url = AbuseService.BASE_ABUSE_URL + '/' + abuse.id + '/messages'
+
+ return this.authHttp.get>(url)
+ .pipe(
+ catchError(res => this.restExtractor.handleError(res))
+ )
+ }
+
+ deleteAbuseMessage (abuse: UserAbuse, abuseMessage: AbuseMessage) {
+ const url = AbuseService.BASE_ABUSE_URL + '/' + abuse.id + '/messages/' + abuseMessage.id
+
+ return this.authHttp.delete(url)
+ .pipe(
+ map(this.restExtractor.extractDataBool),
+ catchError(res => this.restExtractor.handleError(res))
+ )
+ }
+
getPrefefinedReasons (type: AbuseFilter) {
let reasons: { id: AbusePredefinedReasonsString, label: string, description?: string, help?: string }[] = [
{
diff --git a/client/src/app/shared/shared-moderation/index.ts b/client/src/app/shared/shared-moderation/index.ts
index 41c910ffe..c8082d4b3 100644
--- a/client/src/app/shared/shared-moderation/index.ts
+++ b/client/src/app/shared/shared-moderation/index.ts
@@ -1,5 +1,6 @@
export * from './report-modals'
+export * from './abuse-message-modal.component'
export * from './abuse.service'
export * from './account-block.model'
export * from './account-blocklist.component'
diff --git a/client/src/app/shared/shared-moderation/shared-moderation.module.ts b/client/src/app/shared/shared-moderation/shared-moderation.module.ts
index 8fa9ee794..b5b6daf27 100644
--- a/client/src/app/shared/shared-moderation/shared-moderation.module.ts
+++ b/client/src/app/shared/shared-moderation/shared-moderation.module.ts
@@ -4,15 +4,16 @@ import { SharedFormModule } from '../shared-forms/shared-form.module'
import { SharedGlobalIconModule } from '../shared-icons'
import { SharedMainModule } from '../shared-main/shared-main.module'
import { SharedVideoCommentModule } from '../shared-video-comment'
+import { AbuseMessageModalComponent } from './abuse-message-modal.component'
import { AbuseService } from './abuse.service'
import { BatchDomainsModalComponent } from './batch-domains-modal.component'
import { BlocklistService } from './blocklist.service'
import { BulkService } from './bulk.service'
+import { AccountReportComponent, CommentReportComponent, VideoReportComponent } from './report-modals'
import { UserBanModalComponent } from './user-ban-modal.component'
import { UserModerationDropdownComponent } from './user-moderation-dropdown.component'
import { VideoBlockComponent } from './video-block.component'
import { VideoBlockService } from './video-block.service'
-import { VideoReportComponent, AccountReportComponent, CommentReportComponent } from './report-modals'
@NgModule({
imports: [
@@ -29,7 +30,8 @@ import { VideoReportComponent, AccountReportComponent, CommentReportComponent }
VideoReportComponent,
BatchDomainsModalComponent,
CommentReportComponent,
- AccountReportComponent
+ AccountReportComponent,
+ AbuseMessageModalComponent
],
exports: [
@@ -39,7 +41,8 @@ import { VideoReportComponent, AccountReportComponent, CommentReportComponent }
VideoReportComponent,
BatchDomainsModalComponent,
CommentReportComponent,
- AccountReportComponent
+ AccountReportComponent,
+ AbuseMessageModalComponent
],
providers: [
diff --git a/client/src/assets/images/feather/message-circle.svg b/client/src/assets/images/feather/message-circle.svg
new file mode 100644
index 000000000..4b21b32b6
--- /dev/null
+++ b/client/src/assets/images/feather/message-circle.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/client/src/sass/application.scss b/client/src/sass/application.scss
index be510c08f..7ed900574 100644
--- a/client/src/sass/application.scss
+++ b/client/src/sass/application.scss
@@ -32,6 +32,7 @@ body {
--secondaryColor: #{$secondary-color};
--greyForegroundColor: #{$grey-foreground-color};
+ --greyBackgroundColor: #{$grey-background-color};
--menuBackgroundColor: #{$menu-background};
--menuForegroundColor: #{$menu-color};
diff --git a/client/src/sass/include/_variables.scss b/client/src/sass/include/_variables.scss
index 7b95bb8cc..130462b89 100644
--- a/client/src/sass/include/_variables.scss
+++ b/client/src/sass/include/_variables.scss
@@ -92,6 +92,7 @@ $variables: (
--secondaryColor: var(--secondaryColor),
--greyForegroundColor: var(--greyForegroundColor),
+ --greyBackgroundColor: var(--greyBackgroundColor),
--menuBackgroundColor: var(--menuBackgroundColor),
--menuForegroundColor: var(--menuForegroundColor),
diff --git a/server/models/abuse/abuse-message.ts b/server/models/abuse/abuse-message.ts
index f7721c87d..fce20f7a7 100644
--- a/server/models/abuse/abuse-message.ts
+++ b/server/models/abuse/abuse-message.ts
@@ -94,6 +94,8 @@ export class AbuseMessageModel extends Model {
return {
id: this.id,
+ createdAt: this.createdAt,
+
byModerator: this.byModerator,
message: this.message,
diff --git a/shared/models/moderation/abuse/abuse-message.model.ts b/shared/models/moderation/abuse/abuse-message.model.ts
index 02072d5ce..642496646 100644
--- a/shared/models/moderation/abuse/abuse-message.model.ts
+++ b/shared/models/moderation/abuse/abuse-message.model.ts
@@ -4,6 +4,7 @@ export interface AbuseMessage {
id: number
message: string
byModerator: boolean
+ createdAt: Date | string
account: AccountSummary
}
|