More Team Roles, and Admin stuff

This commit is contained in:
Troplo 2020-11-21 22:54:25 +11:00
parent 8d9ce2ed14
commit 70fa581cff
21 changed files with 682 additions and 177 deletions

View File

@ -1,5 +1,6 @@
module.exports = {
port: process.env.PORT || 23981,
sessionSecret: process.env.SESSION_SECRET || 'iouydhtrfguyrthgftryhgidrhytgidhytiglriltnhgrhtiuygrthiugritghiyutrcginhrtijghurfcuhjgnioergjfuiehtiehtiehyritheithreifbhgehfbdxhbkvfdbhjkvgdkhnjUIYIRUiuiuYIYI3i42yiuyIUYIU4yiu$YUI#YUI$3mvsazr57;',
imageUploadTeams: process.env.TEAMUPLOADS || "C:\\Users\\matth\\Documents\\GitHub\\Kaverti-Team-Images"
imageUploadTeams: process.env.TEAMUPLOADS || "C:\\Users\\matth\\Documents\\GitHub\\Kaverti-Team-Images",
maintenance: process.env.MAINTENANCE || false
}

View File

@ -54,6 +54,7 @@
"vue-matomo": "^3.14.0-0",
"vue-router": "^2.7.0",
"vue-router-sitemap": "^0.0.4",
"vuedraggable": "^2.24.3",
"vuejs-paginator": "^2.0.2",
"vuetify": "^2.3.8",
"vuex": "^2.1.1"

View File

@ -3,7 +3,7 @@ module.exports = function(vuex) {
let errors = []
if(res.response === undefined || res.response.data.errors === undefined) {
errors.push('Something went wrong connecting to the Kaverti service, maybe try again later.')
errors.push('Something went wrong connecting to the Kaverti service, please try again later.')
} else {
res.response.data.errors.forEach(error => {
let path = error.path
@ -15,7 +15,6 @@ module.exports = function(vuex) {
errors.push(error.message[0].toUpperCase() + error.message.slice(1))
})
}
if(errors.length) {
vuex.commit('setAjaxErrors', errors)
vuex.commit('setAjaxErrorsModalState', true)

View File

@ -100,6 +100,37 @@
</div>
</template>
<template v-if='teams.length'>
<div class='search_box__results__header search_box__results__header--divider'>Teams</div>
<div
class='search_box__results__search_all'
:class='{
"search_box__results--highlight": highlightIndex === getHighlightIndex("teams header")
}'
ref='teams header'
@mouseover='highlightIndex = getHighlightIndex("teams header")'
@click='goToSearch'
>
<div class='search_box__results__icon'><font-awesome-icon :icon='["fa", "search"]' /></div>
<div>
Search all teams containing '<strong>{{searchField}}</strong>'
</div>
</div>
<div
class='search_box__results__team'
:class='{
"search_box__results--highlight": highlightIndex === getHighlightIndex("teams", index)
}'
v-for='(team, index) in teams'
:key='"team-result-" + index'
ref='teams'
@mouseover='highlightIndex = getHighlightIndex("teams", index)'
@click='goToSearch'
>
<div class='search_box__results__title'>{{team.name}}</div>
</div>
</template>
<div class='search_box__results__message' v-if='!threads.length && !users.length && !loading'>
Uh oh! There were no results for the query: '<strong>{{searchField}}</strong>'
</div>
@ -132,7 +163,8 @@
MinQueryLength: 2,
threads: [],
users: []
users: [],
teams: []
}
},
computed: {
@ -193,7 +225,17 @@
}
return ret;
}
} else if(group === 'teams' || group === 'teams header') {
let ret = 0;
if(this.threads.length) {
ret += 1 + this.threads.length;
}
if(group === 'teams') {
ret += 1 + index;
}
return ret;
}
},
//Produces relative group and index
//from overall highlight index
@ -216,6 +258,12 @@
} else {
return { group: 'users', index: index-1 };
}
} else if(this.teams.length) {
if(index === 0) {
return { group: 'teams header', index: null };
} else {
return { group: 'teams', index: index-1 };
}
}
},
setKeyHighlight (e) {
@ -279,7 +327,11 @@
this.$router.push('/thread/' + thread.slug + '/' + thread.id);
} else if (group === 'users header') {
this.$router.push('/search/users/' + searchEncoded);
} else {
} else if(group === 'teams') {
this.$router.push('/t/' + this.teams[index].username);
} else if(group === 'teams header') {
this.$router.push('/search/teams/' + searchEncoded);
} else {
this.$router.push('/search/threads/' + searchEncoded);
}
@ -295,6 +347,7 @@
this.loading = true;
this.threads = [];
this.users = [];
this.teams = [];
this.axios
.get(process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIVERSION + '/' + 'kaverti/search/thread?q=' + q)
@ -311,6 +364,14 @@
this.loading = false;
})
.catch(AjaxErrorHandler(this.$store));
this.axios
.get(process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIVERSION + '/' + 'kaverti/search/team?q=' + q)
.then(res => {
this.teams = res.data.teams.slice(0, 5);
this.loading = false;
})
.catch(AjaxErrorHandler(this.$store));
}
},
mounted () {

View File

@ -0,0 +1,48 @@
<template>
<div
class='user_display'
@click='$router.push("/user/" + user.username)'
>
<team-icon :user='user' size='small'></team-icon>
<div class='user_display__username'>
{{user.username}}
</div>
</div>
</template>
<script>
import TeamIcon from './TeamIcon'
export default {
name: 'UserDisplay',
props: ['user'],
components: {TeamIcon
},
}
</script>
<style lang='scss' scoped>
@import '../assets/scss/variables.scss';
.user_display {
align-items: center;
background: #fff;
border: thin solid $color__gray--darker;
border-radius: 0.25rem;
cursor: pointer;
display: flex;
flex-direction: row;
margin-bottom: 1rem;
padding: 0.25rem 0.5rem;
transition: box-shadow 0.2s;
&:hover {
@extend .shadow_border--hover;
}
@at-root #{&}__username {
font-size: 1.25rem;
font-weight: 400;
margin-left: 1rem;
}
}
</style>

View File

@ -0,0 +1,168 @@
<template>
<info-tooltip class='avatar_icon' :noEvents='user === null'>
<template slot='content'>
<template v-if='userData'>
<div class='avatar_icon__header'>
<figure class="avatar_icon__icon--small picture_circle">
<img
:src = userPicture
>
</figure>&nbsp;
<div class='avatar_icon__header_info'>
<span class='avatar_icon__username' @click.stop='goToUser'>
{{proxyUser.username}}
</span>
<span class='avatar_icon__date'>Created: {{proxyUser.createdAt | formatDate('date') }}</span>
</div>
</div>
<div class='avatar_icon__description' v-if='proxyUser.description'>
{{proxyUser.description | stripTags | truncate(30)}}
</div>
</template>
<template v-else>Loading...</template>
</template>
<figure
slot="display"
class='avatar_icon__icon picture_circle'
:class='{
"avatar_icon__icon--small": size === "small",
"avatar_icon__icon--tiny": size === "tiny"
}'
@click.stop="goToUser">
<img
:src = userPicture
>
</figure>
</info-tooltip>
</template>
<script>
import InfoTooltip from './InfoTooltip'
import AjaxErrorHandler from '../assets/js/errorHandler'
export default {
name: 'AvatarIcon',
props: ['user', 'size'],
components: { InfoTooltip },
data () {
return {
userData: null
}
},
computed: {
//So that you never access a null variable
proxyUser () {
if(this.userData) {
//Data loaded via api
return this.userData;
} else if (this.user) {
//Data provided as a prop
return this.user;
}
return {};
},
letter () {
if(this.proxyUser.username && !this.proxyUser.picture) {
return this.proxyUser.username[0].toUpperCase();
} else {
return '';
}
},
userPicture () {
if(this.user && this.user.approved && !this.user.banned && this.user.picture !== 'default') {
return this.user.picture
} else if(this.user && this.user.banned) {
return "https://cdn.kaverti.com/teams/unknown-light.png"
} else if(this.user && !this.user.banned && !this.user.approved && this.$store.state.theme === 'light') {
return "https://cdn.kaverti.com/teams/pending-light.png"
} else if(this.user && !this.user.banned && !this.user.approved && this.$store.state.theme === 'dark') {
return "https://cdn.kaverti.com/teams/pending-dark.png"
} else if(this.user && !this.user.banned && !this.user.approved) {
return "https://cdn.kaverti.com/teams/pending-light.png"
} else {
return "https://cdn.kaverti.com/teams/unknown-light.png"
}
}
},
methods: {
loadUser () {
//If user is already loaded or no user provided as a prop
if(this.userData || this.user === null) return;
this.axios
.get(process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIVERSION + '/' + 'teams/view/' + this.proxyUser.username)
.then((res) => {
this.userData = res.data;
})
.catch(AjaxErrorHandler(this.$store));
},
goToUser () {
if(this.user === null) return;
this.$router.push('/user/' + this.user.username)
}
},
mounted() { this.loadUser(); }
}
</script>
<style lang='scss'>
@import '../assets/scss/variables.scss';
.avatar_icon {
@at-root #{&}__icon {
font-size: 0.7rem;
margin-right: 0.25rem;
color: rgba(0, 0, 0, 0.87);
}
@at-root #{&}__header {
display: flex;
align-items: center;
}
@at-root #{&}__icon {
height: 3rem;
width: 3rem;
line-height: 3rem;
cursor: pointer;
@include text($font--role-emphasis, 2rem);
text-align: center;
border-radius: 100%;
color: #fff;
@at-root #{&}--small {
height: 3rem;
width: 3rem;
font-size: 1.75rem;
line-height: 2.5rem;
}
@at-root #{&}--tiny {
height: 1.5rem;
width: 1.5rem;
font-size: 1rem;
line-height: 1.5rem;
}
}
@at-root #{&}__header_info {
display: flex;
flex-direction: column;
height: 2.5rem;
}
@at-root #{&}__username {
cursor: pointer;
}
@at-root #{&}__date {
color: $color__darkgray--primary;
font-size: 0.9rem;
}
@at-root #{&}__description {
margin-top: 0.25rem;
font-size: 0.9rem;
}
}
</style>

View File

@ -0,0 +1,5 @@
<template>
<main>
</main>
</template>

View File

@ -57,6 +57,40 @@
}}
</div>
</transition>
<transition name='fade' mode='out-in'>
<div class='search__results' key='results' v-if='teams && teams.length && !loadingTeams'>
<h2>Teams</h2>
<team-display v-for='user in teams.slice(0, 5)' :key='"search-user-" + user.id' :user='user'></team-display>
<div
class='search__item search__more' v-if='users.length > 5'
@click='$router.push("/search/users/" + $route.params.q)'
>
<font-awesome-icon :icon='["fa", "user"]' fixed-width />
View all matching teams
</div>
</div>
<div
key='loading'
v-if='loadingTeams'
>
<h2>Teams</h2>
<user-placeholder></user-placeholder>
</div>
<div
class='overlay_message search__overlay_message'
v-if='showNoResults || queryTooShort'
key='no results'
>
<i class="far fa-exclamation-circle" />
{{queryTooShort ?
"Search term is too short." :
"Uh oh! There were no results."
}}
</div>
</transition>
</div>
</template>
@ -66,8 +100,9 @@
import UserPlaceholder from '../UserPlaceholder'
import ThreadDisplay from '../ThreadDisplay'
import ThreadDisplayPlaceholder from '../ThreadDisplayPlaceholder'
import TeamDisplay from '../TeamDisplay'
import AjaxErrorHandler from '../../assets/js/errorHandler'
import AjaxErrorHandler from '../../assets/js/errorHandler'
import logger from '../../assets/js/logger'
export default {
@ -76,7 +111,8 @@
UserDisplay,
UserPlaceholder,
ThreadDisplay,
ThreadDisplayPlaceholder
ThreadDisplayPlaceholder,
TeamDisplay
},
data () {
return {
@ -84,7 +120,10 @@
loadingThreads: false,
users: [],
loadingUsers: false
loadingUsers: false,
teams: [],
loadingTeams: false,
}
},
computed: {
@ -121,6 +160,17 @@
})
.catch(AjaxErrorHandler(this.$store))
},
getTeams () {
this.loadingTeams = true;
this.axios
.get(process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIVERSION + '/' + 'kaverti/search/team?q=' + this.$route.params.q)
.then(res => {
this.loadingTeams = false;
this.teams = res.data.teams;
})
.catch(AjaxErrorHandler(this.$store))
},
getResults () {
if(this.queryTooShort) return;
@ -128,7 +178,8 @@
this.getThreads();
this.getUsers();
}
this.getTeams();
}
},
watch: {
'$route.params': 'getResults'

View File

@ -56,18 +56,31 @@
<div class="section">
<div class="">
<h1>Roles:</h1>
<scroll-load
key='user-row'
v-if='roles.length'
:loading='loading'
@loadNext='fetchData'
>
<div class="column is-10" v-for='role in roles' :key='"user-row" + role.name' v-show="role">
<b-tag class="is-large">{{role.name}}</b-tag>
</div>
<br>
<b-button @click="toggleRoleCreate"><i class="fas fa-plus"></i> Add Role</b-button>
</scroll-load>
<ul class="list-group mb-2">
<draggable
class="list-group"
tag="ul"
v-model="roles"
v-bind="dragOptions"
>
<transition-group type="transition">
<li
class="list-group-item"
v-for="role in roles"
:key="role.priority"
>
<i
aria-hidden="true"
></i>
<b-tag class="is-large">{{ role.name }} <b-tag @click="toggleRoleCreate"><i @click="toggleRoleCreate" class="fas fa-pencil"></i></b-tag></b-tag>
</li>
</transition-group>
</draggable>
</ul>
<b-button @click="saveRoles()">Save Role Order</b-button>
&nbsp;
<b-button class="is-info" @click="toggleRoleCreate()"><i class="fas fa-plus"></i> Add Role</b-button>
</div>
</div>
<p name='fade' mode='out-in'>
@ -81,15 +94,18 @@
import LoadingMessage from '../LoadingMessage';
import ScrollLoad from '../ScrollLoad';
import ModalWindow from "@/components/ModalWindow";
import draggable from 'vuedraggable'
import throttle from 'lodash.throttle';
import AjaxErrorHandler from '../../assets/js/errorHandler';
export default {
name: 'TeamMembers',
name: 'TeamRoles',
components: {
LoadingMessage,
// eslint-disable-next-line vue/no-unused-components
ScrollLoad,
ModalWindow
ModalWindow,
draggable
},
data () {
return {
@ -99,12 +115,13 @@ export default {
roles: [],
team: [],
loading: true,
loading: false,
offset: 0,
limit: 15,
showTeamTab: 0,
showRoleModal: false,
createTeamModal: false,
drag: false,
tRole: {
name: '',
@ -132,6 +149,28 @@ export default {
}
},
methods: {
// eslint-disable-next-line no-unused-vars
updateListSortOrder() {
const newList = [...this.roles].map((item, index) => {
const newSort = index + 1;
item.priority = newSort;
return item;
});
this.roles = newList;
},
saveRoles() {
this.updateListSortOrder()
this.axios.put(process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIVERSION + `/` + `teams/admin/roles/modify/` + this.$route.params.username, {
roles: this.roles
}).then(() => {
this.tRole.loading = false
this.closeAccountModal()
}).catch(e => {
this.tRole.loading = false
AjaxErrorHandler(this.$store)(e)
})
},
clearTeamErrors() {
this.tcreateProd.errors.username = ''
this.tcreateProd.errors.name = ''
@ -140,7 +179,9 @@ export default {
this.showRoleModal = false
},
addRole() {
let postParams = {
this.tRole.loading = true
this.axios.post(process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIVERSION + `/` + `teams/admin/roles/create/` + this.$route.params.username, {
name: this.tRole.name,
administrator: this.tRole.administrator,
@ -151,16 +192,14 @@ export default {
changeTeamPrivacy: this.tRole.changeTeamPrivacy,
submitTeamItems: this.tRole.submitTeamItems,
priority: this.tRole.priority
}
this.tRole.loading = true
this.axios.post(process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIVERSION + `/` + `teams/admin/roles/create/` + this.$route.params.username, postParams).then(res => {
res()
}).then(() => {
this.tRole.loading = false
this.closeAccountModal()
this.fetchData()
}).catch(e => {
this.tRole.loading = false
AjaxErrorHandler(this.$store)(e);
AjaxErrorHandler(this.$store)(e)
this.fetchData()
})
},
toggleRoleCreate() {
@ -174,9 +213,12 @@ export default {
this.axios
.get( process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIVERSION + '/' + 'teams/view/' + this.$route.params.username + "/roles")
.then(res => {
this.roles.push(...res.data);
this.roles = res.data.filter(role => role.priority);
//this.roles.push(...res.data);
this.loading = /*loading =*/ false;
//If returned data is less than the limit
//then there must be no more pages to paginate
if(res.data.length < this.limit) {
@ -230,6 +272,16 @@ export default {
mounted () {
this.fetchData();
},
computed: {
dragOptions() {
return {
animation: 200,
group: "description",
disabled: false,
ghostClass: "ghost"
};
},
},
watch: {
tableSort: 'resetFetchData',
roleSelected: 'resetFetchData',
@ -239,3 +291,24 @@ export default {
}
}
</script>
<style>
.flip-list-move {
transition: transform 0.5s;
}
.no-move {
transition: transform 0s;
}
.ghost {
opacity: 0.5;
background: #c8ebfb;
}
.list-group {
min-height: 20px;
}
.list-group-item {
cursor: move;
}
.list-group-item i {
cursor: pointer;
}
</style>

View File

@ -134,6 +134,7 @@ const AdminMarketplace = () => import('./components/routes/AdminMarketplace')
const Licenses = () => import('./components/routes/LICENSES')
const ConnectionProblems = () => import('./components/routes/ConnectionProblems')
const Maintenance = () => import('./components/routes/Maintenance')
const Contributors = () => import('./components/routes/Contributors')
const Inventory = () => import('./components/routes/Inventory')
@ -238,6 +239,7 @@ const router = new VueRouter({
] },
{ path: '/forum', redirect: '/category/all', component: Index },
{ path: '/connection', component: ConnectionProblems },
{ path: '/maintenance', component: Maintenance },
{ path: '/contributors', component: Contributors },
{ path: '/forums', redirect: '/category/all', component: Index },
{ path: '/search/:q', component: Search },

View File

@ -9107,6 +9107,11 @@ sort-keys@^2.0.0:
dependencies:
is-plain-obj "^1.0.0"
sortablejs@1.10.2:
version "1.10.2"
resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.10.2.tgz#6e40364d913f98b85a14f6678f92b5c1221f5290"
integrity sha512-YkPGufevysvfwn5rfdlGyrGjt7/CRHwvRPogD/lC+TnvcN29jDpCifKP+rBqf+LRldfXSTh+0CGLcSg0VIxq3A==
source-list-map@^2.0.0:
version "2.0.1"
resolved "https://npm.open-registry.dev/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
@ -10210,6 +10215,13 @@ vue@^2.6.11:
resolved "https://npm.open-registry.dev/vue/-/vue-2.6.11.tgz#76594d877d4b12234406e84e35275c6d514125c5"
integrity sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ==
vuedraggable@^2.24.3:
version "2.24.3"
resolved "https://registry.yarnpkg.com/vuedraggable/-/vuedraggable-2.24.3.tgz#43c93849b746a24ce503e123d5b259c701ba0d19"
integrity sha512-6/HDXi92GzB+Hcs9fC6PAAozK1RLt1ewPTLjK0anTYguXLAeySDmcnqE8IC0xa7shvSzRjQXq3/+dsZ7ETGF3g==
dependencies:
sortablejs "1.10.2"
vuejs-paginator@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/vuejs-paginator/-/vuejs-paginator-2.0.2.tgz#89792bb33cf73f4ddbd329485f174e23acf0f12c"

View File

@ -59,6 +59,10 @@ let Errors = {
'This category has already been created',
400
],
maintenance: [
'Kaverti is currently under routine maintenance, website access has been restricted, please try again later.',
400
],
accountDoesNotExist: [
'This account does not exist',
400

View File

@ -9,6 +9,7 @@ module.exports = (sequelize, DataTypes) => {
let TeamRoles = sequelize.define('TeamRoles', {
name: {
type: DataTypes.STRING,
allowNull: false,
validate: {
isString(val) {
if (typeof val !== 'string') {
@ -55,7 +56,8 @@ module.exports = (sequelize, DataTypes) => {
},
priority: {
type: DataTypes.BIGINT,
default: 1
default: 1,
allowNull: false,
},
teamId: {
type: DataTypes.BIGINT

View File

@ -18,6 +18,7 @@
"@sendgrid/mail": "^7.2.5",
"axios": "^0.19.0",
"bcryptjs": "^2.4.3",
"bluebird": "^3.7.2",
"body-parser": "^1.19.0",
"compression": "^1.7.3",
"connect-multiparty": "^2.2.0",

32
routes/maintenance.js Normal file
View File

@ -0,0 +1,32 @@
let express = require('express')
let router = express.Router()
const auth = require('../lib/authUserInfo')
const Errors = require('../lib/errors')
let { Settings, Sequelize } = require('../models')
router.get('*', async(req, res, next) => {
try {
throw Errors.maintenance
} catch (err) { next(err) }
})
router.post('*', async(req, res, next) => {
try {
throw Errors.maintenance
} catch (err) { next(err) }
})
router.put('*', async(req, res, next) => {
try {
throw Errors.maintenance
} catch (err) { next(err) }
})
router.options('*', async(req, res, next) => {
try {
res.status(200)
res.json({success: true})
} catch (err) { next(err) }
})
module.exports = router

View File

@ -2,7 +2,7 @@ let express = require('express')
let router = express.Router()
const auth = require('../lib/auth')
let { Post, Ban, Thread, User, Category, Sequelize } = require('../models')
let { Post, Ban, Team, Thread, User, Category, Sequelize } = require('../models')
const Errors = require('../lib/errors')
const { setRandomFallback } = require('bcryptjs')
@ -159,4 +159,28 @@ router.get('/user', async(req, res, next) => {
} catch (e) { next(e) }
})
router.get('/team', async(req, res, next) => {
try {
let searchString = req.query.q
let offset = +req.query.offset || 0
let limit = 10
let teams = await Team.findAll({
where: {
username: { $like: '%' + searchString + '%' }
},
order: [ ['username', 'DESC'] ],
attributes: {exclude: ['banReason']},
limit,
offset
})
res.json({
teams,
offset: teams.length < limit ? null : offset + limit,
next: teams.length < limit ? null : limit
})
} catch (e) { next(e) }
})
module.exports = router

View File

@ -1,59 +0,0 @@
let express = require('express')
let router = express.Router()
const auth = require('../lib/auth')
const Errors = require('../lib/errors')
let { Settings, Ban, Sequelize } = require('../models')
router.get('/', async(req, res, next) => {
try {
let settings = await Settings.get()
if(!settings) throw Errors.noSettings
res.json(settings.toJSON())
} catch (e) { next(e) }
})
router.all('*', auth, (req, res, next) => {
if(req.userData.admin) {
next()
} else {
res.status(401)
res.json({
errors: [Errors.requestNotAuthorized]
})
}
})
router.put('/', auth, async(req, res, next) => {
try {
throw Errors.featureDisabledState
await Ban.ReadOnlyMode(req.userData.username)
let params = {}
if(req.body.siteName) {
params.siteName = req.body.siteName
}
if(req.body.siteDesc !== undefined) {
params.siteDesc = req.body.siteDesc
}
if(req.body.showDescription !== undefined) {
params.showDescription = req.body.showDescription
}
if(req.body.bannerEnabled !== undefined) {
params.bannerEnabled = req.body.bannerEnabled
}
if(req.body.bannerText !== undefined) {
params.bannerText = req.body.bannerText
}
let updatedSettings = await Settings.set(params)
res.json(params)
} catch (e) { next(e) }
})
module.exports = router

35
routes/state.js Normal file
View File

@ -0,0 +1,35 @@
let express = require('express')
let router = express.Router()
const auth = require('../lib/auth')
const Errors = require('../lib/errors')
let { Settings, Ban, Sequelize } = require('../models')
router.get('/', async(req, res, next) => {
try {
let settings = await Settings.findOne({
where: {
id: 1
},
attributes: { exclude: ['id', 'createdAt', 'updatedAt'] }
})
if(!settings) throw Errors.noSettings
res.json(settings.toJSON())
} catch (e) { next(e) }
})
router.all('*', auth, (req, res, next) => {
if(req.userData.admin) {
next()
} else {
res.status(401)
res.json({
errors: [Errors.requestNotAuthorized]
})
}
})
module.exports = router

View File

@ -48,6 +48,7 @@ const sgMail = require('@sendgrid/mail');
const MailGen = require('mailgen')
const crypto = require("crypto")
const cryptoRandomString = require("crypto-random-string")
let Promise = require('bluebird');
const rateLimit = require("express-rate-limit");
let upload = multer({
storage: multer.memoryStorage(),
@ -154,13 +155,92 @@ router.post('/roles/create/:username', auth, async(req, res, next) => {
priority: req.body.priority,
teamId: team.id
}
await TeamRoles.create(makeRole)
let teamCreate = await TeamRoles.create(makeRole)
res.status(200)
res.json({success: true})
res.json(teamCreate.toJSON())
} else if (!teamJoinTest) {
res.status(400)
res.json({success: false})
}
} else {
throw Errors.teamDoesNotExist
}
} catch (e) { next(e) }
})
router.put('/roles/modify/:username/:id', auth, async(req, res, next) => {
try {
let team = await Team.findOne({
where: {username: req.params.username}
});
if(team) {
let queryObj3 = {
where: {userId: req.userData.UserId, teamId: team.id},
}
if(team.banned) {
res.status(200)
res.json({success: false})
}
let teamJoinTest = await TeamMembers.findOne(queryObj3)
if (teamJoinTest) {
if(req.body.name) {
let find = await TeamRoles.findOne({
where: {
id: req.params.id,
teamId: team.id
}
})
if(find) {
let update = await TeamRoles.update({
priority: req.body.priority,
name: req.body.name,
administrator: req.body.administrator,
inviteUsers: req.body.inviteUsers,
changeTeamMeta: req.body.changeTeamMeta,
forumAdministrator: req.body.forumAdministrator,
moderateForumThreads: req.body.moderateForumThreads,
changeTeamPrivacy: req.body.changeTeamPrivacy,
submitTeamItems: req.body.submitTeamItems,
}, {
where: {
id: req.params.id,
teamId: team.id
}
})
res.status(200)
res.json({success: true})
} else {
res.status(400)
res.json({success: false})
}
} else if(req.body.priority && !req.body.name) {
let find = await TeamRoles.findOne({
where: {
id: req.params.id,
teamId: team.id
}
})
if(find) {
await TeamRoles.update({priority: req.body.priority}, {
where: {
id: req.params.id,
teamId: team.id
}
})
res.status(200)
res.json({success:true})
} else {
res.status(400)
res.json({success: false})
}
} else {
res.status(400)
res.json({success: false})
}
} else if (!teamJoinTest) {
res.status(400)
res.json({success: false})
}
} else {
throw Errors.teamDoesNotExist
}
@ -168,46 +248,5 @@ router.post('/roles/create/:username', auth, async(req, res, next) => {
})
router.post('/admin/', auth, async(req, res, next) => {
try {
await Ban.ReadOnlyMode(req.userData.username)
let team = await Team.findOne({
where: { username: req.params.username }
})
if(team) {
if(team.banned) {
throw Errors.teamBanned
}
let queryObj3 = {
where: {userId: req.userData.UserId, teamId: team.id},
}
let teamJoinTest = await TeamMembers.findOne(queryObj3)
if(teamJoinTest) {
throw Errors.joinedTeam
}
let role = await TeamRoles.findOne({
where: {teamId: team.id, name: "Members"}
})
let join = {
userId: req.userData.UserId,
teamId: team.id,
roles: {"deprecated": "deprecated"}
}
console.log(role)
let roleUser = {
UserId: req.userData.UserId,
TeamId: team.id,
RoleId: role.id
}
await TeamMembers.create(join)
await TeamMemberRole.create(roleUser)
res.status(200)
res.json({success: true})
} else {
throw Errors.teamDoesNotExist
}
} catch (e) { next(e) }
})
module.exports = router;

View File

@ -66,7 +66,6 @@ const passport = require('passport');
const specs = swaggerJsdoc(options);
const csrf = require('csurf')
const csrfProtection = csrf({ cookie: true })
if(process.env.NODE_ENV === 'production') {
app.set('trust proxy', 1);
}
@ -80,45 +79,52 @@ app.use(expAutoSan.all);
if(process.env.NODE_ENV !== 'test' && process.env.NODE_ENV !== 'production') {
app.use(require('morgan')('dev'))
}
app.use('/api/v1/user/', require('./routes/user'))
app.use('/api/v1/passkey', require('./routes/user_passkey'))
app.use('/api/v1/admin/admin_token', require('./routes/admin_token'))
app.use('/api/v1/admin/passkey', require('./routes/user_passkey'))
app.use('/api/v1/forums/category', require('./routes/category'))
app.use('/api/v1/forums/thread', require('./routes/thread'))
app.use('/api/v1/users/notification', require('./routes/notification'))
app.use('/api/v1/forums/post', require('./routes/post'))
app.use('/api/v1/kaverti/state', require('./routes/settings'))
app.use('/api/v1/users/report', require('./routes/report'))
app.use('/api/v1/users/unban-request', require('./routes/UnbanRequest'))
app.use('/api/v1/admin/ban', require('./routes/ban'))
app.use('/api/v1/kaverti/search', require('./routes/search'))
app.use('/api/v1/log', require('./routes/log'))
app.use('/api/v1/forums/poll', require('./routes/poll'))
app.use('/api/v1/forums/link_preview', require('./routes/link_preview'))
app.use('/api/v1/kaverti/stats', require('./routes/stats'))
app.use('/api/v1/users/login_status', require('./routes/login_status'))
app.use('/api/v1/users/', require('./routes/userutils'))
app.use('/api/v1/admin/killsession', require('./routes/admin_kill_session'))
app.use('/api/v1/admin/ban', require('./routes/ban'))
app.use('/api/v1/kaverti/job-apply', require('./routes/StaffApplications'))
app.use('/api/v1/admin/', require('./routes/admin'))
app.use('/api/v1/users/render', require('./routes/avatar'))
app.use('/api/v1/users/render/', require('./routes/avatar'))
app.use('/api/v1/userinfo', require('./routes/userinfo'))
app.use('/api/v1/wall', require('./routes/user_wall'))
app.use('/api/v1/chat/conversation', require('./routes/conversation'));
app.use('/api/v1/chat/message', require('./routes/message'));
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(specs, { explorer: true }));
app.use('/api/v1/teams/', require('./routes/team'))
app.use('/api/v1/teams/admin/', require('./routes/team_admin'))
app.use('/api/v1/teams/wall/', require('./routes/team_wall'))
app.use('/api/v1/marketplace', require('./routes/marketplace'))
app.use('/api/v1/inventory', require('./routes/inventory'))
app.use('/api/v1/transactions', require('./routes/transactions'))
app.use(require('./lib/errorHandler'))
app.use(profanity.init);
app.set('trust proxy', true)
if(!config.maintenance) {
app.use('/api/v1/user/', require('./routes/user'))
app.use('/api/v1/passkey', require('./routes/user_passkey'))
app.use('/api/v1/admin/admin_token', require('./routes/admin_token'))
app.use('/api/v1/admin/passkey', require('./routes/user_passkey'))
app.use('/api/v1/forums/category', require('./routes/category'))
app.use('/api/v1/forums/thread', require('./routes/thread'))
app.use('/api/v1/users/notification', require('./routes/notification'))
app.use('/api/v1/forums/post', require('./routes/post'))
app.use('/api/v1/kaverti/state', require('./routes/state'))
app.use('/api/v1/users/report', require('./routes/report'))
app.use('/api/v1/users/unban-request', require('./routes/UnbanRequest'))
app.use('/api/v1/admin/ban', require('./routes/ban'))
app.use('/api/v1/kaverti/search', require('./routes/search'))
app.use('/api/v1/log', require('./routes/log'))
app.use('/api/v1/forums/poll', require('./routes/poll'))
app.use('/api/v1/forums/link_preview', require('./routes/link_preview'))
app.use('/api/v1/kaverti/stats', require('./routes/stats'))
app.use('/api/v1/users/login_status', require('./routes/login_status'))
app.use('/api/v1/users/', require('./routes/userutils'))
app.use('/api/v1/admin/killsession', require('./routes/admin_kill_session'))
app.use('/api/v1/admin/ban', require('./routes/ban'))
app.use('/api/v1/kaverti/job-apply', require('./routes/StaffApplications'))
app.use('/api/v1/admin/', require('./routes/admin'))
app.use('/api/v1/users/render', require('./routes/avatar'))
app.use('/api/v1/users/render/', require('./routes/avatar'))
app.use('/api/v1/userinfo', require('./routes/userinfo'))
app.use('/api/v1/wall', require('./routes/user_wall'))
app.use('/api/v1/chat/conversation', require('./routes/conversation'));
app.use('/api/v1/chat/message', require('./routes/message'));
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(specs, {explorer: true}));
app.use('/api/v1/teams/', require('./routes/team'))
app.use('/api/v1/teams/admin/', require('./routes/team_admin'))
app.use('/api/v1/teams/wall/', require('./routes/team_wall'))
app.use('/api/v1/marketplace', require('./routes/marketplace'))
app.use('/api/v1/inventory', require('./routes/inventory'))
app.use('/api/v1/transactions', require('./routes/transactions'))
app.use(require('./lib/errorHandler'))
app.set('trust proxy', true)
} else {
app.use('/api/v1/userinfo', require('./routes/userinfo'))
app.use('/api/v1/kaverti/state', require('./routes/state'))
app.use('/api/v1/', require('./routes/maintenance'))
app.use(require('./lib/errorHandler'))
app.set('trust proxy', true)
}
function main () {
let server = app.listen(config.port, () => {
console.log('Initialized')