diff --git a/html/src/app.js b/html/src/app.js
index b566dd22..7f95574a 100644
--- a/html/src/app.js
+++ b/html/src/app.js
@@ -408,10 +408,19 @@ speechSynthesis.getVoices();
})
.then(({data, status}) => {
if (status === 200) {
- if (data && data.success === Object(data.success)) {
+ if (!data) {
+ return data;
+ }
+ var text = '';
+ if (data.success === Object(data.success)) {
+ text = data.success.message;
+ } else if (data.OK === String(data.OK)) {
+ text = data.OK;
+ }
+ if (text) {
new Noty({
type: 'success',
- text: escapeTag(data.success.message)
+ text: escapeTag(text)
}).show();
}
return data;
@@ -2987,10 +2996,7 @@ speechSynthesis.getVoices();
}
this.isPlayerModerationsLoading = true;
this.expirePlayerModerations();
- Promise.all([
- this.getPlayerModerations()
- // this.getPlayerModerationsAgainstMe();
- ])
+ Promise.all([this.getPlayerModerations(), this.getAvatarModerations()])
.finally(() => {
this.isPlayerModerationsLoading = false;
})
@@ -3011,18 +3017,6 @@ speechSynthesis.getVoices();
});
};
- API.getPlayerModerationsAgainstMe = function () {
- return this.call('auth/user/playermoderated', {
- method: 'GET'
- }).then((json) => {
- var args = {
- json
- };
- this.$emit('PLAYER-MODERATION:LIST', args);
- return args;
- });
- };
-
/*
params: {
moderated: string,
@@ -3065,6 +3059,126 @@ speechSynthesis.getVoices();
});
};
+ // API: AvatarModeration
+
+ API.cachedAvatarModerations = new Map();
+
+ API.getAvatarModerations = function () {
+ return this.call('auth/user/avatarmoderations', {
+ method: 'GET'
+ }).then((json) => {
+ var args = {
+ json
+ };
+ this.$emit('AVATAR-MODERATION:LIST', args);
+ return args;
+ });
+ };
+
+ /*
+ params: {
+ avatarModerationType: string,
+ targetAvatarId: string
+ }
+ */
+ API.sendAvatarModeration = function (params) {
+ return this.call('auth/user/avatarmoderations', {
+ method: 'POST',
+ params
+ }).then((json) => {
+ var args = {
+ json,
+ params
+ };
+ this.$emit('AVATAR-MODERATION', args);
+ return args;
+ });
+ };
+
+ /*
+ params: {
+ avatarModerationType: string,
+ targetAvatarId: string
+ }
+ */
+ API.deleteAvatarModeration = function (params) {
+ return this.call(
+ `auth/user/avatarmoderations?targetAvatarId=${encodeURIComponent(
+ params.targetAvatarId
+ )}&avatarModerationType=${encodeURIComponent(
+ params.avatarModerationType
+ )}`,
+ {
+ method: 'DELETE'
+ }
+ ).then((json) => {
+ var args = {
+ json,
+ params
+ };
+ this.$emit('AVATAR-MODERATION:DELETE', args);
+ return args;
+ });
+ };
+
+ API.$on('AVATAR-MODERATION', function (args) {
+ args.ref = this.applyAvatarModeration(args.json);
+ });
+
+ API.$on('AVATAR-MODERATION:LIST', function (args) {
+ // TODO: compare with cachedAvatarModerations
+ this.cachedAvatarModerations = new Map();
+ for (var json of args.json) {
+ this.applyAvatarModeration(json);
+ }
+ });
+
+ API.$on('AVATAR-MODERATION:DELETE', function (args) {
+ this.cachedAvatarModerations.delete(args.params.targetAvatarId);
+
+ // update avatar dialog
+ var D = $app.avatarDialog;
+ if (
+ D.visible &&
+ args.params.avatarModerationType === 'block' &&
+ D.id === args.params.targetAvatarId
+ ) {
+ D.isBlocked = false;
+ }
+ });
+
+ API.applyAvatarModeration = function (json) {
+ // fix inconsistent Unix time response
+ if (typeof json.created === 'number') {
+ json.created = new Date(json.created).toJSON();
+ }
+
+ var ref = this.cachedAvatarModerations.get(json.targetAvatarId);
+ if (typeof ref === 'undefined') {
+ ref = {
+ avatarModerationType: '',
+ created: '',
+ targetAvatarId: '',
+ ...json
+ };
+ this.cachedAvatarModerations.set(ref.targetAvatarId, ref);
+ } else {
+ Object.assign(ref, json);
+ }
+
+ // update avatar dialog
+ var D = $app.avatarDialog;
+ if (
+ D.visible &&
+ ref.avatarModerationType === 'block' &&
+ D.id === ref.targetAvatarId
+ ) {
+ D.isBlocked = true;
+ }
+
+ return ref;
+ };
+
// API: Favorite
API.cachedFavorites = new Map();
@@ -15115,6 +15229,7 @@ speechSynthesis.getVoices();
id: '',
ref: {},
isFavorite: false,
+ isBlocked: false,
isQuestFallback: false,
treeData: [],
fileSize: '',
@@ -15157,6 +15272,7 @@ speechSynthesis.getVoices();
D.cacheLocked = false;
D.isQuestFallback = false;
D.isFavorite = API.cachedFavoritesByObjectId.has(avatarId);
+ D.isBlocked = API.cachedAvatarModerations.has(avatarId);
var ref2 = API.cachedAvatars.get(avatarId);
if (typeof ref2 !== 'undefined') {
D.ref = ref2;
@@ -15298,6 +15414,24 @@ speechSynthesis.getVoices();
return args;
});
break;
+ case 'Block Avatar':
+ API.sendAvatarModeration({
+ avatarModerationType: 'block',
+ targetAvatarId: D.id
+ }).then((args) => {
+ this.$message({
+ message: 'Avatar blocked',
+ type: 'success'
+ });
+ return args;
+ });
+ break;
+ case 'Unblock Avatar':
+ API.deleteAvatarModeration({
+ avatarModerationType: 'block',
+ targetAvatarId: D.id
+ });
+ break;
case 'Make Public':
API.saveAvatar({
id: D.id,
diff --git a/html/src/index.pug b/html/src/index.pug
index 4d4cd923..a0fb07f6 100644
--- a/html/src/index.pug
+++ b/html/src/index.pug
@@ -2002,11 +2002,13 @@ html
el-tooltip(v-else placement="top" content="Add to favorites" :disabled="hideTooltips")
el-button(type="default" icon="el-icon-star-off" circle @click="avatarDialogCommand('Add Favorite')" style="margin-left:5px")
el-dropdown(trigger="click" @command="avatarDialogCommand" size="small" style="margin-left:5px")
- el-button(type="default" icon="el-icon-more" circle)
+ el-button(:type="avatarDialog.isBlocked ? 'danger' : 'default'" icon="el-icon-more" circle style="margin-left:5px")
el-dropdown-menu(#default="dropdown")
el-dropdown-item(icon="el-icon-refresh" command="Refresh") Refresh
el-dropdown-item(icon="el-icon-check" command="Select Avatar") Select Avatar
el-dropdown-item(v-if="/quest/.test(avatarDialog.ref.tags)" icon="el-icon-check" command="Select Fallback Avatar") Select Fallback Avatar
+ el-dropdown-item(v-if="avatarDialog.isBlocked" icon="el-icon-circle-check" command="Unblock Avatar" style="color:#F56C6C") Unblock Avatar
+ el-dropdown-item(v-else icon="el-icon-circle-close" command="Block Avatar") Block Avatar
el-dropdown-item(v-if="avatarDialog.ref.authorId !== API.currentUser.id" icon="el-icon-picture-outline" command="Previous Images") Previous Images
template(v-if="avatarDialog.ref.authorId === API.currentUser.id")
el-dropdown-item(v-if="avatarDialog.ref.releaseStatus === 'public'" icon="el-icon-user-solid" command="Make Private" divided) Make Private