This commit is contained in:
lesion
2019-05-30 12:04:14 +02:00
parent 69792b518e
commit 6099d538c0
47 changed files with 1220 additions and 998 deletions

View File

@@ -4,7 +4,7 @@ const User = require('./models/user')
const Auth = {
async fillUser(req, res, next) {
if (!req.user) return next(new Error('ERROR! No user'))
if (!req.user) return next()
req.user = await User.findOne({
where: { id: { [Op.eq]: req.user.id }, is_active: true }
})

View File

@@ -1,5 +1,5 @@
const { User, Event, Comment, Tag } = require('../model')
const config = require('../../../config')
const { SHARED_CONF } = require('../../../config')
const Mastodon = require('mastodon-api')
// const Sequelize = require('sequelize')
// const Op = Sequelize.Op
@@ -13,7 +13,7 @@ const botController = {
bot: null,
async initialize () {
const settings = await settingsController.settings()
if (!settings.mastodon_auth) return
if (!settings.mastodon_auth || !settings.mastodon_auth.access_token) return
const mastodon_auth = settings.mastodon_auth
botController.bot = new Mastodon({
access_token: mastodon_auth.access_token,
@@ -46,7 +46,7 @@ const botController = {
const { access_token, instance } = mastodon_auth
const bot = new Mastodon({ access_token, api_url: `https://${instance}/api/v1/` })
const status = `${event.title} @ ${event.place.name} ${moment(event.start_datetime).format('ddd, D MMMM HH:mm')} -
${event.description.length > 200 ? event.description.substr(0, 200) + '...' : event.description} - ${event.tags.map(t => '#' + t.tag).join(' ')} ${config.baseurl}/event/${event.id}`
${event.description.length > 200 ? event.description.substr(0, 200) + '...' : event.description} - ${event.tags.map(t => '#' + t.tag).join(' ')} ${SHARED_CONF.baseurl}/event/${event.id}`
let media
if (event.image_path) {

View File

@@ -3,6 +3,7 @@ const moment = require('moment')
const { Op } = require('sequelize')
const lodash = require('lodash')
const { User, Event, Comment, Tag, Place, Notification } = require('../model')
const Sequelize = require('sequelize')
const eventController = {
@@ -19,8 +20,26 @@ const eventController = {
},
async getMeta(req, res) {
const places = await Place.findAll()
const tags = await Tag.findAll()
const places = await Place.findAll({
group: ['place.id'],
order: [[Sequelize.fn("COUNT", Sequelize.col('events.id')), 'DESC']],
attributes: {
include: [[Sequelize.fn("COUNT", Sequelize.col('events.id')), 'eventsCount']],
exclude: ['createdAt', 'updatedAt']
},
include: { model: Event, attributes: [] }
})
const tags = await Tag.findAll({
group: ['tag'],
order: [[Sequelize.fn("COUNT", Sequelize.col('events.id')), 'DESC']],
includeIgnoreAttributes:false,
attributes: {
include: [[Sequelize.fn("COUNT", Sequelize.col('events.id')), 'eventsCount']],
exclude: ['createdAt', 'updatedAt']
},
include: { model: Event, attributes: [] }})
res.json({ tags, places })
},
@@ -67,7 +86,14 @@ const eventController = {
async get(req, res) {
const id = req.params.event_id
const event = await Event.findByPk(id, { include: [User, Tag, Comment, Place] })
const event = await Event.findByPk(id, { include:
[
Tag,
Comment,
{ model: Place, attributes: ['name', 'address'] }
] ,
order: [ [Comment, 'id', 'DESC'] ]
})
res.json(event)
},

View File

@@ -1,4 +1,6 @@
const { Settings } = require('../model')
const { SHARED_CONF } = require('../../../config')
const Mastodon = require('mastodon-api')
const settingsController = {
async setAdminSetting (key, value) {
@@ -14,6 +16,42 @@ const settingsController = {
res.json(settings)
},
async getAuthURL(req, res) {
const instance = req.body.instance
const callback = `${SHARED_CONF.baseurl}/api/settings/oauth`
const { client_id, client_secret } = await Mastodon.createOAuthApp(`https://${instance}/api/v1/apps`,
SHARED_CONF.title, 'read write', callback)
const url = await Mastodon.getAuthorizationUrl(client_id, client_secret,
`https://${instance}`, 'read write', callback)
await settingsController.setAdminSetting('mastodon_auth', { client_id, client_secret, instance })
res.json(url)
},
async code(req, res) {
const code = req.query.code
let client_id, client_secret, instance
const callback = `${SHARED_CONF.baseurl}/api/settings/oauth`
console.error('sono dentro CODEEEEEEEEEE', code)
const settings = await settingsController.settings()
console.log(settings);
({ client_id, client_secret, instance } = settings.mastodon_auth)
try {
const token = await Mastodon.getAccessToken(client_id, client_secret, code,
`https://${instance}`, callback)
const mastodon_auth = { client_id, client_secret, access_token: token, instance }
console.error(mastodon_auth)
await settingsController.setAdminSetting('mastodon_auth', mastodon_auth)
res.redirect('/admin')
} catch (e) {
res.json(e)
}
},
async settings () {
const settings = await Settings.findAll()
const map = {}

View File

@@ -2,14 +2,12 @@ const fs = require('fs')
const path = require('path')
const crypto = require('crypto')
const jwt = require('jsonwebtoken')
const Mastodon = require('mastodon-api')
const { Op } = require('sequelize')
const jsonwebtoken = require('jsonwebtoken')
const User = require('../models/user')
const config = require('../../../config')
const { SECRET_CONF, SHARED_CONF } = require('../../../config')
const mail = require('../mail')
const { Event, Tag, Place } = require('../models/event')
const settingsController = require('./settings')
const eventController = require('./event')
const userController = {
@@ -17,13 +15,13 @@ const userController = {
// find the user
const user = await User.findOne({ where: { email: { [Op.eq]: req.body && req.body.email } } })
if (!user) {
res.status(404).json({ success: false, message: 'AUTH_FAIL' })
res.status(403).json({ success: false, message: 'auth.fail' })
} else if (user) {
if (!user.is_active) {
res.status(403).json({ success: false, message: 'NOT_CONFIRMED' })
res.status(403).json({ success: false, message: 'auth.not_confirmed' })
// check if password matches
} else if (!await user.comparePassword(req.body.password)) {
res.status(403).json({ success: false, message: 'AUTH_FAIL' })
res.status(403).json({ success: false, message: 'auth.fail' })
} else {
// if user is found and password is right
// create a token
@@ -33,7 +31,7 @@ const userController = {
email: user.email,
scope: [user.is_admin ? 'admin' : 'user']
},
config.secret
SECRET_CONF.secret
)
res.json({token: accessToken})
@@ -58,8 +56,12 @@ const userController = {
if (event.image_path) {
const old_path = path.resolve(__dirname, '..', '..', 'uploads', event.image_path)
const old_thumb_path = path.resolve(__dirname, '..', '..', 'uploads', 'thumb', event.image_path)
await fs.unlink(old_path)
await fs.unlink(old_thumb_path)
try {
await fs.unlink(old_path)
await fs.unlink(old_thumb_path)
} catch (e) {
console.error(e)
}
}
await event.destroy()
res.sendStatus(200)
@@ -160,61 +162,14 @@ const userController = {
return res.json(newEvent)
},
async getAuthURL(req, res) {
const instance = req.body.instance
const is_admin = req.body.admin && req.user.is_admin
const callback = `${config.baseurl}/${is_admin ? 'admin/oauth' : 'settings'}`
const { client_id, client_secret } = await Mastodon.createOAuthApp(`https://${instance}/api/v1/apps`,
config.title, 'read write', callback)
const url = await Mastodon.getAuthorizationUrl(client_id, client_secret,
`https://${instance}`, 'read write', callback)
if (is_admin) {
await settingsController.setAdminSetting('mastodon_auth', { client_id, client_secret, instance })
} else {
req.user.mastodon_auth = { client_id, client_secret, instance }
await req.user.save()
}
res.json(url)
},
async code(req, res) {
const { code, is_admin } = req.body
let client_id, client_secret, instance
const callback = `${config.baseurl}/${is_admin ? 'admin/oauth' : 'settings'}`
if (is_admin) {
const settings = await settingsController.settings();
({ client_id, client_secret, instance } = settings.mastodon_auth)
} else {
({ client_id, client_secret, instance } = req.user.mastodon_auth)
}
try {
const token = await Mastodon.getAccessToken(client_id, client_secret, code,
`https://${instance}`, callback)
const mastodon_auth = { client_id, client_secret, access_token: token, instance }
if (is_admin) {
await settingsController.setAdminSetting('mastodon_auth', mastodon_auth)
res.json(instance)
} else {
req.user.mastodon_auth = mastodon_auth
await req.user.save()
// await bot.add(req.user, token)
res.json(req.user)
}
} catch (e) {
res.json(e)
}
},
async forgotPassword(req, res) {
const email = req.body.email
const user = await User.findOne({ where: { email: { [Op.eq]: email } } })
if (!user) return res.sendStatus(200)
user.recover_code = crypto.randomBytes(16).toString('hex')
mail.send(user.email, 'recover', { user, config })
mail.send(user.email, 'recover', { user, config: SHARED_CONF })
await user.save()
res.sendStatus(200)
},
@@ -229,13 +184,17 @@ const userController = {
async updatePasswordWithRecoverCode(req, res) {
const recover_code = req.body.recover_code
if (!recover_code) return res.sendStatus(400)
const password = req.body.password
if (!recover_code || !password) return res.sendStatus(400)
const user = await User.findOne({ where: { recover_code: { [Op.eq]: recover_code } } })
if (!user) return res.sendStatus(400)
user.password = password
await user.save()
res.sendStatus(200)
try {
await user.save()
res.sendStatus(200)
} catch(e) {
res.sendStatus(400)
}
},
async current(req, res) {
@@ -253,7 +212,7 @@ const userController = {
const user = await User.findByPk(req.body.id)
if (user) {
if (!user.is_active && req.body.is_active) {
await mail.send(user.email, 'confirm', { user, config })
await mail.send(user.email, 'confirm', { user, config: SHARED_CONF })
}
await user.update(req.body)
res.json(user)
@@ -263,25 +222,29 @@ const userController = {
},
async register(req, res) {
console.error('register !!', req)
const n_users = await User.count()
try {
// the first registered user will be an active admin
if (n_users === 0) {
// the first registered user will be an active admin
req.body.is_active = req.body.is_admin = true
} else {
req.body.is_active = false
}
const user = await User.create(req.body)
try {
mail.send([user.email, config.admin], 'register', { user, config })
mail.send([user.email, SECRET_CONF.admin], 'register', { user, config: SHARED_CONF })
} catch (e) {
console.error(e)
return res.status(400).json(e)
}
const payload = { email: user.email }
const token = jwt.sign(payload, config.secret)
const token = jwt.sign(payload, SECRET_CONF.secret)
res.json({ user, token })
} catch (e) {
console.error(e)
res.status(404).json(e)
}
}

View File

@@ -1,5 +1,6 @@
const Sequelize = require('sequelize')
const conf = require('../../config.js')
const db = new Sequelize(conf.db)
db.sync()
const { SECRET_CONF } = require('../../config.js')
const db = new Sequelize(SECRET_CONF.db)
// db.sync()
module.exports = db

View File

@@ -5,10 +5,23 @@ const eventController = require('./controller/event')
const exportController = require('./controller/export')
const userController = require('./controller/user')
const settingsController = require('./controller/settings')
const config = require('../../config')
const { SECRET_CONF } = require('../../config')
const cookieParser = require('cookie-parser')
const botController = require('./controller/bot')
const jwt = require('express-jwt')({secret: config.secret})
const expressJwt = require('express-jwt')
const jwt = expressJwt({
secret: SECRET_CONF.secret,
credentialsRequired: false,
getToken: req => {
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
return req.headers.authorization.split(' ')[1];
} else if (req.cookies && req.cookies['auth._token.local']) {
const tmp = req.cookies['auth._token.local'].split(' ');
return tmp[1]
}
return null
}
})
const storage = require('./storage')({
destination: 'uploads/'
@@ -16,7 +29,7 @@ const storage = require('./storage')({
const upload = multer({ storage })
const api = express.Router()
api.use(cookieParser())
// AUTH
api.post('/auth/login', userController.login)
api.post('/auth/logout', userController.logout)
@@ -81,7 +94,7 @@ api.get('/export/:type', exportController.export)
api.get('/event/:month/:year', eventController.getAll)
// mastodon oauth auth
api.post('/user/getauthurl', jwt, isAuth, userController.getAuthURL)
api.post('/user/code', jwt, isAuth, userController.code)
api.post('/settings/getauthurl', jwt, isAuth, isAdmin, settingsController.getAuthURL)
api.get('/settings/oauth', jwt, isAuth, isAdmin, settingsController.code)
module.exports = api

View File

@@ -1,40 +1,40 @@
const Email = require('email-templates')
const path = require('path')
const config = require('../../config')
const { SECRET_CONF, SHARED_CONF } = require('../../config')
const moment = require('moment')
moment.locale(config.locale)
moment.locale(SHARED_CONF.locale)
const mail = {
send (addresses, template, locals) {
const email = new Email({
views: { root: path.join(__dirname, 'emails') },
views: { root: path.join(__dirname, '..', 'emails') },
juice: true,
juiceResources: {
preserveImportant: true,
webResources: {
relativeTo: path.join(__dirname, 'emails')
relativeTo: path.join(__dirname, '..', 'emails')
}
},
message: {
from: `${config.title} <${config.smtp.auth.user}>`
from: `${SHARED_CONF.title} <${SECRET_CONF.smtp.auth.user}>`
},
send: true,
i18n: {
locales: ['en', 'es', 'it'],
defaultLocale: config.locale
directory: path.join(__dirname, '..', '..', 'locales', 'email'),
defaultLocale: SHARED_CONF.locale
},
transport: config.smtp
transport: SECRET_CONF.smtp
})
return email.send({
template,
message: {
to: addresses,
bcc: config.admin
bcc: SECRET_CONF.admin
},
locals: {
...locals,
locale: config.locale,
config,
locale: SHARED_CONF.locale,
config: SHARED_CONF,
datetime: datetime => moment(datetime).format('ddd, D MMMM HH:mm')
}
})

View File

@@ -10,19 +10,23 @@ const Event = db.define('event', {
end_datetime: { type: Sequelize.DATE, index: true },
image_path: Sequelize.STRING,
is_visible: Sequelize.BOOLEAN,
activitypub_id: { type: Sequelize.STRING, index: true },
// activitypub_ids: { type: Sequelize.ARRAY, index}
activitypub_id: { type: Sequelize.BIGINT, index: true },
activitypub_ids: {
type: Sequelize.ARRAY(Sequelize.BIGINT),
index: true,
defaultValue: []
}
})
const Tag = db.define('tag', {
tag: { type: Sequelize.STRING, index: true, unique: true, primaryKey: true },
tag: { type: Sequelize.STRING, index: true, unique: true, },
color: { type: Sequelize.STRING }
})
const Comment = db.define('comment', {
activitypub_id: { type: Sequelize.STRING, index: true },
activitypub_id: { type: Sequelize.BIGINT, index: true },
data: Sequelize.JSON,
url: Sequelize.STRING,
// url: Sequelize.STRING,
author: Sequelize.STRING,
text: Sequelize.STRING
})

View File

@@ -28,8 +28,8 @@ DiskStorage.prototype._handleFile = function _handleFile(req, file, cb) {
const thumbPath = path.join(destination, 'thumb', filename)
const outStream = fs.createWriteStream(finalPath)
const thumbStream = fs.createWriteStream(thumbPath)
const resizer = sharp().resize(800).jpeg({ quality: 80 })
const thumbnailer = sharp().resize(400).jpeg({ quality: 60 })
const resizer = sharp().resize(800).jpeg({ quality: 90 })
const thumbnailer = sharp().resize(400).jpeg({ quality: 90 })
file.stream.pipe(thumbnailer).pipe(thumbStream)
thumbStream.on('error', e => console.log('thumbStream error ', e))