mirror of
https://iceshrimp.dev/crimekillz/trashposs
synced 2024-11-23 09:23:48 +01:00
なんかもうめっちゃやった
This commit is contained in:
parent
1ebf8a04c4
commit
d5c3464e6f
@ -78,7 +78,7 @@ export default Vue.extend({
|
|||||||
cursor wait !important
|
cursor wait !important
|
||||||
|
|
||||||
> .avatar
|
> .avatar
|
||||||
margin 16px auto 0 auto
|
margin 0 auto 0 auto
|
||||||
width 64px
|
width 64px
|
||||||
height 64px
|
height 64px
|
||||||
background #ddd
|
background #ddd
|
||||||
|
@ -42,15 +42,7 @@ export default define({
|
|||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
(this as any).os.getMeta().then(meta => {
|
(this as any).os.getMeta().then(meta => {
|
||||||
let broadcasts = [];
|
this.broadcasts = meta.broadcasts;
|
||||||
if (meta.broadcasts) {
|
|
||||||
meta.broadcasts.forEach(broadcast => {
|
|
||||||
if (broadcast[lang]) {
|
|
||||||
broadcasts.push(broadcast[lang]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.broadcasts = broadcasts;
|
|
||||||
this.fetching = false;
|
this.fetching = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
<template>
|
||||||
|
<div class="qldxjjsrseehkusjuoooapmsprvfrxyl mk-admin-card">
|
||||||
|
<header>%i18n:@announcements%</header>
|
||||||
|
<textarea v-model="broadcasts"></textarea>
|
||||||
|
<button class="ui" @click="save">%i18n:@save%</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from "vue";
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
broadcasts: '',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
(this as any).os.getMeta().then(meta => {
|
||||||
|
this.broadcasts = JSON.stringify(meta.broadcasts, null, ' ');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
save() {
|
||||||
|
(this as any).api('admin/update-meta', {
|
||||||
|
broadcasts: JSON.parse(this.broadcasts)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
@import '~const.styl'
|
||||||
|
|
||||||
|
.qldxjjsrseehkusjuoooapmsprvfrxyl
|
||||||
|
textarea
|
||||||
|
width 100%
|
||||||
|
min-height 300px
|
||||||
|
|
||||||
|
</style>
|
@ -4,6 +4,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li @click="nav('dashboard')" :class="{ active: page == 'dashboard' }">%fa:chalkboard .fw%%i18n:@dashboard%</li>
|
<li @click="nav('dashboard')" :class="{ active: page == 'dashboard' }">%fa:chalkboard .fw%%i18n:@dashboard%</li>
|
||||||
<li @click="nav('users')" :class="{ active: page == 'users' }">%fa:users .fw%%i18n:@users%</li>
|
<li @click="nav('users')" :class="{ active: page == 'users' }">%fa:users .fw%%i18n:@users%</li>
|
||||||
|
<li @click="nav('announcements')" :class="{ active: page == 'announcements' }">%fa:broadcast-tower .fw%%i18n:@announcements%</li>
|
||||||
<!-- <li @click="nav('drive')" :class="{ active: page == 'drive' }">%fa:cloud .fw%%i18n:@drive%</li> -->
|
<!-- <li @click="nav('drive')" :class="{ active: page == 'drive' }">%fa:cloud .fw%%i18n:@drive%</li> -->
|
||||||
<!-- <li @click="nav('update')" :class="{ active: page == 'update' }">%i18n:@update%</li> -->
|
<!-- <li @click="nav('update')" :class="{ active: page == 'update' }">%i18n:@update%</li> -->
|
||||||
</ul>
|
</ul>
|
||||||
@ -13,6 +14,9 @@
|
|||||||
<x-dashboard/>
|
<x-dashboard/>
|
||||||
<x-charts/>
|
<x-charts/>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-show="page == 'announcements'">
|
||||||
|
<x-announcements/>
|
||||||
|
</div>
|
||||||
<div v-if="page == 'users'">
|
<div v-if="page == 'users'">
|
||||||
<x-suspend-user/>
|
<x-suspend-user/>
|
||||||
<x-unsuspend-user/>
|
<x-unsuspend-user/>
|
||||||
@ -28,6 +32,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from "vue";
|
import Vue from "vue";
|
||||||
import XDashboard from "./admin.dashboard.vue";
|
import XDashboard from "./admin.dashboard.vue";
|
||||||
|
import XAnnouncements from "./admin.announcements.vue";
|
||||||
import XSuspendUser from "./admin.suspend-user.vue";
|
import XSuspendUser from "./admin.suspend-user.vue";
|
||||||
import XUnsuspendUser from "./admin.unsuspend-user.vue";
|
import XUnsuspendUser from "./admin.unsuspend-user.vue";
|
||||||
import XVerifyUser from "./admin.verify-user.vue";
|
import XVerifyUser from "./admin.verify-user.vue";
|
||||||
@ -37,6 +42,7 @@ import XCharts from "../../components/charts.vue";
|
|||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
XDashboard,
|
XDashboard,
|
||||||
|
XAnnouncements,
|
||||||
XSuspendUser,
|
XSuspendUser,
|
||||||
XUnsuspendUser,
|
XUnsuspendUser,
|
||||||
XVerifyUser,
|
XVerifyUser,
|
||||||
|
@ -1,46 +1,60 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mk-welcome">
|
<div class="mk-welcome">
|
||||||
<img ref="pointer" class="pointer" src="/assets/pointer.png" alt="">
|
|
||||||
<button @click="dark">
|
<button @click="dark">
|
||||||
<template v-if="$store.state.device.darkmode">%fa:moon%</template>
|
<template v-if="$store.state.device.darkmode">%fa:moon%</template>
|
||||||
<template v-else>%fa:R moon%</template>
|
<template v-else>%fa:R moon%</template>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<mk-forkit class="forkit"/>
|
||||||
|
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<div class="container">
|
<div class="main">
|
||||||
|
<h1 v-if="name != 'Misskey'">{{ name }}</h1>
|
||||||
|
<h1 v-else><img :src="$store.state.device.darkmode ? 'assets/title.dark.svg' : 'assets/title.light.svg'" :alt="name"></h1>
|
||||||
|
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<span><b>{{ host }}</b></span>
|
<span><b>{{ host }}</b> - <span v-html="'%i18n:@powered-by-misskey%'"></span></span>
|
||||||
<span class="stats" v-if="stats">
|
<span class="stats" v-if="stats">
|
||||||
<span>%fa:user% {{ stats.originalUsersCount | number }}</span>
|
<span>%fa:user% {{ stats.originalUsersCount | number }}</span>
|
||||||
<span>%fa:pencil-alt% {{ stats.originalNotesCount | number }}</span>
|
<span>%fa:pencil-alt% {{ stats.originalNotesCount | number }}</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<main>
|
|
||||||
<div class="about">
|
<p class="desc" v-html="description || '%i18n:common.about%'"></p>
|
||||||
<h1 v-if="name != 'Misskey'">{{ name }}</h1>
|
|
||||||
<h1 v-else><img :src="$store.state.device.darkmode ? 'assets/title.dark.svg' : 'assets/title.light.svg'" :alt="name"></h1>
|
<p class="sign">
|
||||||
<p class="powerd-by" v-if="name != 'Misskey'" v-html="'%i18n:@powered-by-misskey%'"></p>
|
<span class="signup" @click="signup">%i18n:@signup%</span>
|
||||||
<p class="desc" v-html="description || '%i18n:common.about%'"></p>
|
<span class="divider">|</span>
|
||||||
<a ref="signup" @click="signup">📦 %i18n:@signup%</a>
|
<span class="signin" @click="signin">%i18n:@signin%</span>
|
||||||
</div>
|
</p>
|
||||||
<div class="login">
|
|
||||||
<mk-signin/>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
<div class="hashtags">
|
<div class="hashtags">
|
||||||
<router-link v-for="tag in tags" :key="tag" :to="`/tags/${ tag }`" :title="tag">#{{ tag }}</router-link>
|
<router-link v-for="tag in tags" :key="tag" :to="`/tags/${ tag }`" :title="tag">#{{ tag }}</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="broadcasts">
|
||||||
|
<div v-for="broadcast in broadcasts">
|
||||||
|
<h1 v-html="broadcast.title"></h1>
|
||||||
|
<div v-html="broadcast.text"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav">
|
||||||
<mk-nav class="nav"/>
|
<mk-nav class="nav"/>
|
||||||
</div>
|
</div>
|
||||||
<mk-forkit class="forkit"/>
|
|
||||||
<img src="assets/title.dark.svg" :alt="name">
|
<mk-welcome-timeline class="tl" :max="20"/>
|
||||||
</div>
|
|
||||||
<div class="tl">
|
|
||||||
<mk-welcome-timeline :max="20"/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<modal name="signup" width="500px" height="auto" scrollable>
|
<modal name="signup" :class="$store.state.device.darkmode ? 'modal-dark' : 'modal-light'" width="450px" height="auto" scrollable>
|
||||||
<header :class="$style.signupFormHeader">%i18n:@signup%</header>
|
<header class="formHeader">%i18n:@signup%</header>
|
||||||
<mk-signup :class="$style.signupForm"/>
|
<mk-signup class="form"/>
|
||||||
|
</modal>
|
||||||
|
|
||||||
|
<modal name="signin" :class="$store.state.device.darkmode ? 'modal-dark' : 'modal-light'" width="450px" height="auto" scrollable>
|
||||||
|
<header class="formHeader">%i18n:@signin%</header>
|
||||||
|
<mk-signin class="form"/>
|
||||||
</modal>
|
</modal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -57,7 +71,7 @@ export default Vue.extend({
|
|||||||
host,
|
host,
|
||||||
name: 'Misskey',
|
name: 'Misskey',
|
||||||
description: '',
|
description: '',
|
||||||
pointerInterval: null,
|
broadcasts: [],
|
||||||
tags: []
|
tags: []
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -65,6 +79,7 @@ export default Vue.extend({
|
|||||||
(this as any).os.getMeta().then(meta => {
|
(this as any).os.getMeta().then(meta => {
|
||||||
this.name = meta.name;
|
this.name = meta.name;
|
||||||
this.description = meta.description;
|
this.description = meta.description;
|
||||||
|
this.broadcasts = meta.broadcasts;
|
||||||
});
|
});
|
||||||
|
|
||||||
(this as any).api('stats').then(stats => {
|
(this as any).api('stats').then(stats => {
|
||||||
@ -75,19 +90,7 @@ export default Vue.extend({
|
|||||||
this.tags = stats.map(x => x.tag);
|
this.tags = stats.map(x => x.tag);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
mounted() {
|
|
||||||
this.point();
|
|
||||||
this.pointerInterval = setInterval(this.point, 100);
|
|
||||||
},
|
|
||||||
beforeDestroy() {
|
|
||||||
clearInterval(this.pointerInterval);
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
point() {
|
|
||||||
const x = this.$refs.signup.getBoundingClientRect();
|
|
||||||
this.$refs.pointer.style.top = x.top + x.height + 'px';
|
|
||||||
this.$refs.pointer.style.left = x.left + 'px';
|
|
||||||
},
|
|
||||||
signup() {
|
signup() {
|
||||||
this.$modal.show('signup');
|
this.$modal.show('signup');
|
||||||
},
|
},
|
||||||
@ -104,11 +107,40 @@ export default Vue.extend({
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style lang="stylus">
|
||||||
#wait {
|
#wait
|
||||||
right: auto;
|
right auto
|
||||||
left: 15px;
|
left 15px
|
||||||
}
|
|
||||||
|
.v--modal-overlay
|
||||||
|
background rgba(0, 0, 0, 0.4)
|
||||||
|
|
||||||
|
.modal-light
|
||||||
|
.v--modal-box
|
||||||
|
color #777
|
||||||
|
|
||||||
|
.formHeader
|
||||||
|
border-bottom solid 1px #eee
|
||||||
|
|
||||||
|
.modal-dark
|
||||||
|
.v--modal-box
|
||||||
|
background #313543
|
||||||
|
color #fff
|
||||||
|
|
||||||
|
.formHeader
|
||||||
|
border-bottom solid 1px rgba(#000, 0.2)
|
||||||
|
|
||||||
|
.modal-light
|
||||||
|
.modal-dark
|
||||||
|
.form
|
||||||
|
padding 24px 48px 48px 48px
|
||||||
|
|
||||||
|
.formHeader
|
||||||
|
text-align center
|
||||||
|
padding 48px 0 12px 0
|
||||||
|
margin 0 48px
|
||||||
|
font-size 1.5em
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
@ -117,122 +149,85 @@ export default Vue.extend({
|
|||||||
root(isDark)
|
root(isDark)
|
||||||
display flex
|
display flex
|
||||||
min-height 100vh
|
min-height 100vh
|
||||||
|
//background-color #00070F
|
||||||
|
//background-image url('/assets/bg.jpg')
|
||||||
|
//background-position center
|
||||||
|
//background-size cover
|
||||||
|
|
||||||
> .pointer
|
> .forkit
|
||||||
display block
|
|
||||||
position absolute
|
position absolute
|
||||||
z-index 1
|
|
||||||
top 0
|
top 0
|
||||||
right 0
|
right 0
|
||||||
width 180px
|
|
||||||
margin 0 0 0 -180px
|
|
||||||
transform rotateY(180deg) translateX(-10px) translateY(-48px)
|
|
||||||
pointer-events none
|
|
||||||
|
|
||||||
> button
|
> button
|
||||||
position fixed
|
position fixed
|
||||||
z-index 1
|
z-index 1
|
||||||
top 0
|
bottom 64px
|
||||||
left 0
|
left 64px
|
||||||
padding 16px
|
padding 16px
|
||||||
font-size 18px
|
font-size 18px
|
||||||
color #fff
|
color isDark ? #fff : #444
|
||||||
|
|
||||||
display none // TODO
|
|
||||||
|
|
||||||
> .body
|
> .body
|
||||||
flex 1
|
display grid
|
||||||
padding 64px 0 0 0
|
grid-template-rows 0.5fr 0.5fr 64px
|
||||||
text-align center
|
grid-template-columns 1fr 350px
|
||||||
background #578394
|
gap 16px
|
||||||
background-position center
|
width 100%
|
||||||
background-size cover
|
max-width 1200px
|
||||||
|
height 100vh
|
||||||
|
margin 0 auto
|
||||||
|
padding 64px
|
||||||
|
|
||||||
&:before
|
> *
|
||||||
content ''
|
color isDark ? #fff : #444
|
||||||
display block
|
background isDark ? #313543 : #fff
|
||||||
position absolute
|
box-shadow 0 3px 8px rgba(0, 0, 0, 0.2)
|
||||||
top 0
|
//border-radius 8px
|
||||||
left 0
|
overflow auto
|
||||||
right 0
|
|
||||||
bottom 0
|
|
||||||
background rgba(#000, 0.5)
|
|
||||||
|
|
||||||
> .forkit
|
> .main
|
||||||
position absolute
|
grid-row 1
|
||||||
top 0
|
grid-column 1
|
||||||
right 0
|
padding 32px
|
||||||
|
|
||||||
> img
|
> h1
|
||||||
position absolute
|
margin 0
|
||||||
bottom 16px
|
|
||||||
right 16px
|
|
||||||
width 150px
|
|
||||||
|
|
||||||
> .container
|
> img
|
||||||
$aboutWidth = 380px
|
margin -8px 0 0 -16px
|
||||||
$loginWidth = 340px
|
max-width 280px
|
||||||
$width = $aboutWidth + $loginWidth
|
|
||||||
|
|
||||||
> .info
|
> .info
|
||||||
margin 0 auto 16px auto
|
margin 0 auto 16px auto
|
||||||
width $width
|
width $width
|
||||||
font-size 14px
|
font-size 14px
|
||||||
color #fff
|
|
||||||
|
|
||||||
> .stats
|
> .stats
|
||||||
margin-left 16px
|
margin-left 16px
|
||||||
padding-left 16px
|
padding-left 16px
|
||||||
border-left solid 1px #fff
|
border-left solid 1px isDark ? #fff : #444
|
||||||
|
|
||||||
> *
|
> *
|
||||||
margin-right 16px
|
margin-right 16px
|
||||||
|
|
||||||
> main
|
> .sign
|
||||||
display flex
|
font-size 120%
|
||||||
margin auto
|
|
||||||
width $width
|
|
||||||
border-radius 8px
|
|
||||||
overflow hidden
|
|
||||||
box-shadow 0 2px 8px rgba(#000, 0.3)
|
|
||||||
|
|
||||||
> .about
|
> .divider
|
||||||
width $aboutWidth
|
margin 0 16px
|
||||||
color #444
|
|
||||||
background #fff
|
|
||||||
|
|
||||||
> h1
|
> .signin
|
||||||
margin 0 0 16px 0
|
> .signup
|
||||||
padding 32px 32px 0 32px
|
cursor pointer
|
||||||
color #444
|
|
||||||
|
|
||||||
> img
|
&:hover
|
||||||
width 170px
|
color $theme-color
|
||||||
vertical-align bottom
|
|
||||||
|
|
||||||
> .powerd-by
|
|
||||||
margin 16px
|
|
||||||
opacity 0.7
|
|
||||||
|
|
||||||
> .desc
|
|
||||||
margin 0
|
|
||||||
padding 0 32px 16px 32px
|
|
||||||
|
|
||||||
> a
|
|
||||||
display inline-block
|
|
||||||
margin 0 0 32px 0
|
|
||||||
font-weight bold
|
|
||||||
|
|
||||||
> .login
|
|
||||||
width $loginWidth
|
|
||||||
padding 16px 32px 32px 32px
|
|
||||||
background isDark ? #2e3440 : #f5f5f5
|
|
||||||
|
|
||||||
> .hashtags
|
> .hashtags
|
||||||
margin 16px auto
|
margin 16px auto
|
||||||
width $width
|
width $width
|
||||||
font-size 14px
|
font-size 14px
|
||||||
color #fff
|
|
||||||
background rgba(#000, 0.3)
|
background rgba(#000, 0.3)
|
||||||
border-radius 8px
|
border-radius 8px
|
||||||
|
|
||||||
@ -240,20 +235,32 @@ root(isDark)
|
|||||||
display inline-block
|
display inline-block
|
||||||
margin 14px
|
margin 14px
|
||||||
|
|
||||||
> .nav
|
> .broadcasts
|
||||||
display block
|
grid-row 2
|
||||||
margin 16px 0
|
grid-column 1
|
||||||
font-size 14px
|
padding 32px
|
||||||
color #fff
|
|
||||||
|
|
||||||
> .tl
|
> div
|
||||||
margin 0
|
padding 0 0 16px 0
|
||||||
width 410px
|
margin 0 0 16px 0
|
||||||
height 100vh
|
border-bottom 1px solid isDark ? rgba(#000, 0.2) : rgba(#000, 0.05)
|
||||||
text-align left
|
|
||||||
background isDark ? #313543 : #fff
|
|
||||||
|
|
||||||
> *
|
> h1
|
||||||
|
margin 0
|
||||||
|
font-size 1.5em
|
||||||
|
|
||||||
|
> .nav
|
||||||
|
display flex
|
||||||
|
justify-content center
|
||||||
|
align-items center
|
||||||
|
grid-row 3
|
||||||
|
grid-column 1
|
||||||
|
font-size 14px
|
||||||
|
|
||||||
|
> .tl
|
||||||
|
grid-row 1 / 4
|
||||||
|
grid-column 2
|
||||||
|
text-align left
|
||||||
max-height 100%
|
max-height 100%
|
||||||
overflow auto
|
overflow auto
|
||||||
|
|
||||||
@ -264,29 +271,3 @@ root(isDark)
|
|||||||
root(false)
|
root(false)
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style lang="stylus" module>
|
|
||||||
.signupForm
|
|
||||||
padding 24px 48px 48px 48px
|
|
||||||
|
|
||||||
.signupFormHeader
|
|
||||||
padding 48px 0 12px 0
|
|
||||||
margin: 0 48px
|
|
||||||
font-size 1.5em
|
|
||||||
color #777
|
|
||||||
border-bottom solid 1px #eee
|
|
||||||
|
|
||||||
.signinForm
|
|
||||||
padding 24px 48px 48px 48px
|
|
||||||
|
|
||||||
.signinFormHeader
|
|
||||||
padding 48px 0 12px 0
|
|
||||||
margin: 0 48px
|
|
||||||
font-size 1.5em
|
|
||||||
color #777
|
|
||||||
border-bottom solid 1px #eee
|
|
||||||
|
|
||||||
.nav
|
|
||||||
a
|
|
||||||
color #666
|
|
||||||
</style>
|
|
||||||
|
@ -11,11 +11,17 @@ export const meta = {
|
|||||||
requireAdmin: true,
|
requireAdmin: true,
|
||||||
|
|
||||||
params: {
|
params: {
|
||||||
|
broadcasts: $.arr($.obj()).optional.nullable.note({
|
||||||
|
desc: {
|
||||||
|
'ja-JP': 'ブロードキャスト'
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
disableRegistration: $.bool.optional.nullable.note({
|
disableRegistration: $.bool.optional.nullable.note({
|
||||||
desc: {
|
desc: {
|
||||||
'ja-JP': '招待制か否か'
|
'ja-JP': '招待制か否か'
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -25,6 +31,10 @@ export default (params: any) => new Promise(async (res, rej) => {
|
|||||||
|
|
||||||
const set = {} as any;
|
const set = {} as any;
|
||||||
|
|
||||||
|
if (ps.broadcasts) {
|
||||||
|
set.broadcasts = ps.broadcasts;
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof ps.disableRegistration === 'boolean') {
|
if (typeof ps.disableRegistration === 'boolean') {
|
||||||
set.disableRegistration = ps.disableRegistration;
|
set.disableRegistration = ps.disableRegistration;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user