aaa
This commit is contained in:
parent
a28b22b6b1
commit
193498d708
BIN
frontend/public/favicon.png
Normal file
BIN
frontend/public/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 86 KiB |
41
migrations/20200908042210-blog.js
Normal file
41
migrations/20200908042210-blog.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
up: (queryInterface, Sequelize) => {
|
||||
return queryInterface.createTable('BlogPosts', {
|
||||
id: {
|
||||
type: Sequelize.INTEGER,
|
||||
primaryKey: true,
|
||||
autoIncrement: true
|
||||
},
|
||||
createdAt: Sequelize.DATE,
|
||||
updatedAt: Sequelize.DATE,
|
||||
name: {
|
||||
type: Sequelize.TEXT,
|
||||
allowNull: false
|
||||
},
|
||||
slug: Sequelize.TEXT,
|
||||
content: {
|
||||
type: Sequelize.TEXT,
|
||||
allowNull: false
|
||||
},
|
||||
postNumber: Sequelize.INTEGER,
|
||||
removed: {
|
||||
type: Sequelize.BOOLEAN,
|
||||
defaultValue: false
|
||||
},
|
||||
|
||||
UserId: Sequelize.INTEGER,
|
||||
comments: {
|
||||
type: Sequelize.BOOLEAN,
|
||||
defaultValue: true
|
||||
},
|
||||
}, {
|
||||
charset: 'utf8mb4'
|
||||
})
|
||||
},
|
||||
|
||||
down: (queryInterface, Sequelize) => {
|
||||
return queryInterface.dropTable('BlogPosts');
|
||||
}
|
||||
};
|
29
migrations/20200908070345-statelogo.js
Normal file
29
migrations/20200908070345-statelogo.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
module.exports = {
|
||||
up(queryInterface, Sequelize) {
|
||||
return Promise.all([
|
||||
queryInterface.addColumn(
|
||||
'Settings',
|
||||
'logo',
|
||||
{
|
||||
type: Sequelize.STRING,
|
||||
required: true,
|
||||
default: "https://cdn.kaverti.com/logo.png",
|
||||
allowNull: false
|
||||
},
|
||||
),
|
||||
queryInterface.addColumn(
|
||||
'Settings',
|
||||
'icon',
|
||||
{
|
||||
type: Sequelize.STRING,
|
||||
required: true,
|
||||
default: "/favicon.png",
|
||||
allowNull: false
|
||||
},
|
||||
)
|
||||
]);
|
||||
},
|
||||
down: (queryInterface, Sequelize) => {
|
||||
return queryInterface.removeColumn('Users', 'theme');
|
||||
}
|
||||
};
|
135
models/blog.js
Normal file
135
models/blog.js
Normal file
|
@ -0,0 +1,135 @@
|
|||
let urlSlug = require('url-slug')
|
||||
|
||||
module.exports = (sequelize, DataTypes) => {
|
||||
let Thread = sequelize.define('Thread', {
|
||||
name: {
|
||||
type: DataTypes.TEXT,
|
||||
set (val) {
|
||||
this.setDataValue('name', val)
|
||||
if(val) {
|
||||
this.setDataValue(
|
||||
'slug',
|
||||
//if you don't covert to lowercase it doesn't
|
||||
//correctly slugify diacritics, e.g. thrËad
|
||||
//becomes 'thr-ead' not 'thread'
|
||||
urlSlug(val.toString().toLowerCase() || '') || '_'
|
||||
)
|
||||
}
|
||||
},
|
||||
allowNull: false,
|
||||
validate: {
|
||||
notEmpty: {
|
||||
msg: 'Did you forget something? (Fill this in!)'
|
||||
},
|
||||
len: {
|
||||
args: [4, 256],
|
||||
msg: 'The title must be between 4 and 256 characters'
|
||||
},
|
||||
isString (val) {
|
||||
if(typeof val !== 'string') {
|
||||
throw new sequelize.ValidationError('The title must be a string')
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
slug: DataTypes.TEXT,
|
||||
postsCount: {
|
||||
type: DataTypes.INTEGER,
|
||||
defaultValue: 0
|
||||
},
|
||||
locked: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: false
|
||||
}
|
||||
}, {
|
||||
instanceMethods: {
|
||||
getMeta (limit) {
|
||||
let meta = {}
|
||||
|
||||
let posts = this.Posts
|
||||
let firstPost = posts[0]
|
||||
let lastPost = posts.slice(-1)[0]
|
||||
|
||||
//next url
|
||||
if(!lastPost || lastPost.postNumber+1 === this.postsCount) {
|
||||
meta.nextURL = null
|
||||
} else {
|
||||
meta.nextURL =
|
||||
`/api/v1/blog/post/${this.id}?limit=${limit}&from=${lastPost.postNumber + 1}`
|
||||
}
|
||||
|
||||
//previous url
|
||||
if(!firstPost || firstPost.postNumber === 0) {
|
||||
meta.previousURL = null
|
||||
} else if(firstPost.postNumber - limit < 0) {
|
||||
meta.previousURL =
|
||||
`/api/v1/forums/thread/${this.id}?limit=${firstPost.postNumber}&from=0`
|
||||
} else {
|
||||
meta.previousURL =
|
||||
`/api/v1/forums/thread/${this.id}?limit=${limit}&from=${firstPost.postNumber - limit}`
|
||||
}
|
||||
|
||||
//remaining posts
|
||||
if(lastPost === undefined) {
|
||||
meta.nextPostsCount = 0
|
||||
meta.previousPostsCount = 0
|
||||
meta.postsRemaining = 0
|
||||
} else {
|
||||
let postsRemaining =
|
||||
this.postsCount - lastPost.postNumber - 1
|
||||
|
||||
meta.postsRemaining = postsRemaining
|
||||
|
||||
if(postsRemaining < limit) {
|
||||
meta.nextPostsCount = postsRemaining
|
||||
} else {
|
||||
meta.nextPostsCount = limit
|
||||
}
|
||||
|
||||
if(firstPost.postNumber === 0) {
|
||||
meta.previousPostsCount = 0
|
||||
} else if(firstPost.postNumber - limit < 0) {
|
||||
meta.previousPostsCount = firstPost.postNumber
|
||||
} else {
|
||||
meta.previousPostsCount = limit
|
||||
}
|
||||
}
|
||||
|
||||
return meta
|
||||
}
|
||||
},
|
||||
classMethods: {
|
||||
associate (models) {
|
||||
Thread.belongsTo(models.User)
|
||||
Thread.belongsTo(models.Category)
|
||||
Thread.belongsTo(models.PollQuestion)
|
||||
Thread.hasMany(models.Post, { foreignKeyConstraint: true, onDelete: 'CASCADE' })
|
||||
},
|
||||
includeOptions (from, limit) {
|
||||
let models = sequelize.models
|
||||
|
||||
return [
|
||||
{ model: models.User, attributes: ['username', 'createdAt', 'color', 'picture', 'updatedAt', 'id'] },
|
||||
models.Category,
|
||||
{
|
||||
model: models.Post,
|
||||
where: { postNumber: { $gte: from } },
|
||||
order: [['id', 'ASC']],
|
||||
limit,
|
||||
include: [
|
||||
{ model: models.Thread, attributes: ['slug'] },
|
||||
{ model: models.User, as: 'Likes', attributes: ['username', 'createdAt', 'id', 'color', 'picture'] },
|
||||
{ model: models.User, attributes: ['username', 'createdAt', 'id', 'color', 'picture', 'admin'] },
|
||||
{
|
||||
model: models.Post, as: 'Replies', include:
|
||||
[{ model: models.User, attributes: ['username', 'id', 'color', 'picture'] }]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return Thread
|
||||
}
|
|
@ -42,6 +42,14 @@ module.exports = (sequelize, DataTypes) => {
|
|||
type: DataTypes.STRING,
|
||||
defaultValue: "wss://gateway.kaverti.com"
|
||||
},
|
||||
logo: {
|
||||
type: DataTypes.STRING,
|
||||
defaultValue: "https://cdn.kaverti.com/logo.png"
|
||||
},
|
||||
icon: {
|
||||
type: DataTypes.STRING,
|
||||
defaultValue: "/favicon.png"
|
||||
},
|
||||
RegistrationsDisabled: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: false
|
||||
|
@ -49,7 +57,6 @@ module.exports = (sequelize, DataTypes) => {
|
|||
}, {
|
||||
classMethods: {
|
||||
set (values) {
|
||||
values.id = 1
|
||||
return Settings.upsert(values)
|
||||
},
|
||||
get () {
|
||||
|
|
0
routes/blog.js
Normal file
0
routes/blog.js
Normal file
|
@ -9,7 +9,7 @@ router.get('/:id', async (req, res, next) => {
|
|||
let id = req.params.id
|
||||
let pollQuestion = await PollQuestion.findById(id, {
|
||||
include: [
|
||||
{ model: User, attributes: { exclude: ['hash', 'email'] } },
|
||||
{ model: User, attributes: { exclude: ['hash', 'email', 'emailVerified', 'currency1', 'currency2', 'emailToken', 'passwordResetExpiry', 'passwordResetToken', 'experimentMode', 'developerMode'] } },
|
||||
{ model: PollAnswer, include: [PollVote] }
|
||||
]
|
||||
})
|
||||
|
|
|
@ -44,13 +44,13 @@ router.get('/thread', async (req, res, next) => {
|
|||
include: [
|
||||
{
|
||||
model: Post,
|
||||
include: [{ model: User, attributes: { exclude: ['hash', 'email'] } }],
|
||||
include: [{ model: User, attributes: { exclude: ['hash', 'email', 'emailVerified', 'currency1', 'currency2', 'emailToken', 'passwordResetExpiry', 'passwordResetToken', 'experimentMode', 'developerMode']} }],
|
||||
where: {
|
||||
postNumber: 0
|
||||
}
|
||||
},
|
||||
{ model: Category },
|
||||
{ model: User, attributes: { exclude: ['hash', 'email'] } }
|
||||
{ model: User, attributes: { exclude: ['hash', 'email', 'emailVerified', 'currency1', 'currency2', 'emailToken', 'passwordResetExpiry', 'passwordResetToken', 'experimentMode', 'developerMode'] } }
|
||||
],
|
||||
limit
|
||||
})
|
||||
|
@ -63,14 +63,14 @@ router.get('/thread', async (req, res, next) => {
|
|||
include: [
|
||||
{
|
||||
model: Post,
|
||||
include: [{ model: User, attributes: { exclude: ['hash', 'email'] } }],
|
||||
include: [{ model: User, attributes: { exclude: ['hash', 'email', 'emailVerified', 'currency1', 'currency2', 'emailToken', 'passwordResetExpiry', 'passwordResetToken', 'experimentMode', 'developerMode'] } }],
|
||||
where: {
|
||||
postNumber: 0,
|
||||
plainText: { $like: '%' + searchString + '%' }
|
||||
}
|
||||
},
|
||||
{ model: Category },
|
||||
{ model: User, attributes: { exclude: ['hash', 'email'] } }
|
||||
{ model: User, attributes: { exclude: ['hash', 'email', 'emailVerified', 'currency1', 'currency2', 'emailToken', 'passwordResetExpiry', 'passwordResetToken', 'experimentMode', 'developerMode'] } }
|
||||
],
|
||||
limit
|
||||
})
|
||||
|
@ -112,7 +112,7 @@ router.get('/thread', async (req, res, next) => {
|
|||
$or: whereClause
|
||||
},
|
||||
order: [ ['ThreadId', 'DESC'] ],
|
||||
include: [{ model: User, attributes: { exclude: ['hash', 'email'] } }]
|
||||
include: [{ model: User, attributes: { exclude: ['hash', 'email', 'emailVerified', 'currency1', 'currency2', 'emailToken', 'passwordResetExpiry', 'passwordResetToken', 'experimentMode', 'developerMode'] } }]
|
||||
})
|
||||
|
||||
//Merge latest posts with threads array
|
||||
|
|
|
@ -7,6 +7,8 @@ let { Settings, Ban, Sequelize } = require('../models')
|
|||
router.get('/', async (req, res, next) => {
|
||||
try {
|
||||
let settings = await Settings.get()
|
||||
exclude: ['id']
|
||||
|
||||
|
||||
if(!settings) throw Errors.noSettings
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ router.get('/users', async (req, res, next) => {
|
|||
username
|
||||
},
|
||||
order: [ ['username', 'DESC'] ],
|
||||
attributes: { exclude: ['hash', 'email'] },
|
||||
attributes: { exclude: ['hash', 'email', 'emailVerified', 'currency1', 'currency2', 'emailToken', 'passwordResetExpiry', 'passwordResetToken', 'experimentMode', 'developerMode'] },
|
||||
offset
|
||||
})
|
||||
|
||||
|
|
Loading…
Reference in a new issue