From cc47740582a4f8d64546521bd0c299c7ac477184 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Sat, 25 May 2019 19:18:48 +0530 Subject: [PATCH 01/33] add option to add user from RC_API --- core/server/api/shared/http.js | 5 +- core/server/api/v0.1/authentication.js | 1 + core/server/api/v2/invites.js | 117 ++++++++++++++++++++++++- core/server/api/v2/utils/rc-users.js | 60 +++++++++++++ core/server/data/schema/schema.js | 1 + 5 files changed, 178 insertions(+), 6 deletions(-) create mode 100644 core/server/api/v2/utils/rc-users.js diff --git a/core/server/api/shared/http.js b/core/server/api/shared/http.js index 2b685b7f2d4c..31dbcdd479cd 100644 --- a/core/server/api/shared/http.js +++ b/core/server/api/shared/http.js @@ -28,7 +28,7 @@ const http = (apiImpl) => { id: req.api_key.get('integration_id') }; } - + // NOTE: "external user" is only used in the subscriber app. External user is ID "0". if ((req.user && req.user.id) || (req.user && models.User.isExternalUser(req.user.id))) { user = req.user.id; @@ -82,6 +82,7 @@ const http = (apiImpl) => { if (apiImpl.response && apiImpl.response.format === 'plain') { debug('plain text response'); + return res.send(result); } @@ -93,7 +94,7 @@ const http = (apiImpl) => { docName: frame.docName, method: frame.method }; - + next(err); }); }; diff --git a/core/server/api/v0.1/authentication.js b/core/server/api/v0.1/authentication.js index 284795bd5c02..2f6382b709be 100644 --- a/core/server/api/v0.1/authentication.js +++ b/core/server/api/v0.1/authentication.js @@ -408,6 +408,7 @@ authentication = { } return models.User.add({ + rc_id: '12345678912345678', email: data.email, name: data.name, password: data.password, diff --git a/core/server/api/v2/invites.js b/core/server/api/v2/invites.js index 4b913bed77ba..133bd50f125e 100644 --- a/core/server/api/v2/invites.js +++ b/core/server/api/v2/invites.js @@ -4,6 +4,7 @@ const security = require('../../lib/security'); const mailService = require('../../services/mail'); const urlService = require('../../services/url'); const settingsCache = require('../../services/settings/cache'); +const getRCUsers = require('./utils/rc-users'); const models = require('../../models'); const api = require('./index'); const ALLOWED_INCLUDES = []; @@ -104,9 +105,18 @@ module.exports = { unsafeAttrs: UNSAFE_ATTRS }, query(frame) { - let invite; - let emailData; - + let users; + // let emailData; + let header = { + 'X-Auth-Token': 'AQlnaFgDczayLPngn-HdHABIomE2EjV_LMHAW0lvV1X', + 'X-User-Id': 'AZG7dyTXMJoPhJHE7' + }; + getRCUsers('https://open.rocket.chat/api/v1/users.list', header) + .then((body)=>{ + users = body; + console.log("users"); + }); + // return; // CASE: ensure we destroy the invite before return models.Invite.findOne({email: frame.data.invites[0].email}, frame.options) .then((invite) => { @@ -130,7 +140,8 @@ module.exports = { invitedByEmail: frame.user.get('email'), resetLink: urlService.utils.urlJoin(adminUrl, 'signup', security.url.encodeBase64(invite.get('token')), '/') }; - + console.log("yo"); + console.log(emailData.resetLink); return mailService.utils.generateContent({data: emailData, template: 'invite-user'}); }) .then((emailContent) => { @@ -172,5 +183,103 @@ module.exports = { return Promise.reject(err); }); } + }, + adder: { + statusCode: 201, + options: [ + ], + validation: { + options: { + include: ALLOWED_INCLUDES + }, + data: { + role: { + required: true + }, + apiUrl: { + required: true + } + } + }, + permissions: { + unsafeAttrs: 'role' + }, + query(frame) { + // let invite; + // let emailData; + console.log("yo"); + common.logging.info("yo"+ " ~1"); + let header = { + 'X-Auth-Token': 'AQlnaFgDczayLPngn-HdHABIomE2EjV_LMHAW0lvV1X', + 'X-User-Id': 'AZG7dyTXMJoPhJHE7' + }; + getRCUsers('https://open.rocket.chat/api/v1/users.list', header); + return; + // CASE: ensure we destroy the invite before + // return models.Invite.findOne({email: frame.data.invites[0].email}, frame.options) + // .then((invite) => { + // if (!invite) { + // return; + // } + + // return invite.destroy(frame.options); + // }) + // .then(() => { + // return models.Invite.add(frame.data.invites[0], frame.options); + // }) + // .then((_invite) => { + // invite = _invite; + + // const adminUrl = urlService.utils.urlFor('admin', true); + + // emailData = { + // blogName: settingsCache.get('title'), + // invitedByName: frame.user.get('name'), + // invitedByEmail: frame.user.get('email'), + // resetLink: urlService.utils.urlJoin(adminUrl, 'signup', security.url.encodeBase64(invite.get('token')), '/') + // }; + // console.log("yo"); + // console.log(emailData.resetLink); + // return mailService.utils.generateContent({data: emailData, template: 'invite-user'}); + // }) + // .then((emailContent) => { + // const payload = { + // mail: [{ + // message: { + // to: invite.get('email'), + // subject: common.i18n.t('common.api.users.mail.invitedByName', { + // invitedByName: emailData.invitedByName, + // blogName: emailData.blogName + // }), + // html: emailContent.html, + // text: emailContent.text + // }, + // options: {} + // }] + // }; + + // return api.mail.send(payload, {context: {internal: true}}); + // }) + // .then(() => { + // return models.Invite.edit({ + // status: 'sent' + // }, Object.assign({id: invite.id}, frame.options)); + // }) + // .then((invite) => { + // return invite; + // }) + // .catch((err) => { + // if (err && err.errorType === 'EmailError') { + // const errorMessage = common.i18n.t('errors.api.invites.errorSendingEmail.error', { + // message: err.message + // }); + // const helpText = common.i18n.t('errors.api.invites.errorSendingEmail.help'); + // err.message = `${errorMessage} ${helpText}`; + // common.logging.warn(err.message); + // } + + // return Promise.reject(err); + // }); + } } }; diff --git a/core/server/api/v2/utils/rc-users.js b/core/server/api/v2/utils/rc-users.js new file mode 100644 index 000000000000..3522889e0423 --- /dev/null +++ b/core/server/api/v2/utils/rc-users.js @@ -0,0 +1,60 @@ +const Promise = require('bluebird'); +const request = require('request'); +const common = require('../../../lib/common'); +const models = require('../../../models'); + +module.exports = async function getRCUsers(apiUrl, header) { + const options = { context: { internal: true } }; + + return new Promise((resolve) => { + let users, offset = 0, total = 1, count = 10; + let fetched = false; + for (offset; offset < total;) { + request.get({ url: buidApiUrl(apiUrl, offset, count), headers: header }, function (e, r, body) { + let result = JSON.parse(body); + if (result.success) { + total = result.total; + //offset += result.count; + users = result.users; + console.log(result.users[0]); + // Check if RC gives admin callee result. + // if (users && users[0] && !users[0].password) { + // throw new common.errors.InternalServerError({message: 'Doesnot have admin access in RC.'}); + // } + users.forEach(user => { + models.User.findOne({ rc_id: user._id }, options) + .then((u) => { + // Don't save if User is already in the DB. + if (!u) + saveUser(user, options); + }); + }); + } else { + throw new common.errors.InternalServerError({ message: 'Unable to add users from RC.' }); + } + }); + offset = 1; + } + resolve(fetched); + }) +}; + +function saveUser(user, options) { + // let email = user.emails[0].address; + // user.emails.foreach((e)=>{ + // if (e.verified) { + // email = e.address; + // } + // }); + return models.User.add({ + rc_id: user._id, + email: user._id + '@g.com', + name: user.name, + password: '$2a$10$etxjjsdeTbUC7aG3Od2/EuMUY4iqqXEV4jF0MtXSfsL2RmwJT3Jjm',//user.password.bcrypt, + roles: ['5ce927a694a0da53b54c24e8'] + }, options); +} + +function buidApiUrl(base, offset, count) { + return base + '?' + `offset=${offset}&count=${count}`; +} diff --git a/core/server/data/schema/schema.js b/core/server/data/schema/schema.js index 7f0cf495aa96..94a251006a90 100644 --- a/core/server/data/schema/schema.js +++ b/core/server/data/schema/schema.js @@ -61,6 +61,7 @@ module.exports = { }, users: { id: {type: 'string', maxlength: 24, nullable: false, primary: true}, + rc_id: {type: 'string', maxlength: 17, nullable: true, unique: false}, name: {type: 'string', maxlength: 191, nullable: false}, slug: {type: 'string', maxlength: 191, nullable: false, unique: true}, ghost_auth_access_token: {type: 'string', maxlength: 32, nullable: true}, From 5551d559e342ea43a99c02b3b6bd1563b3182ac4 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Mon, 27 May 2019 21:22:14 +0530 Subject: [PATCH 02/33] add login with access_token and user_id --- core/client | 2 +- core/server/api/v2/session.js | 48 ++++++++++++++++++++++++++++ core/server/api/v2/utils/rc-users.js | 13 +++++--- 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/core/client b/core/client index 8688e659edcc..9a12450bae20 160000 --- a/core/client +++ b/core/client @@ -1 +1 @@ -Subproject commit 8688e659edcc56779178e545488a583d16d5f07d +Subproject commit 9a12450bae20a938f236b930993aa70437cd4193 diff --git a/core/server/api/v2/session.js b/core/server/api/v2/session.js index 63b0405d7f85..677af268046b 100644 --- a/core/server/api/v2/session.js +++ b/core/server/api/v2/session.js @@ -1,8 +1,11 @@ const Promise = require('bluebird'); +const request = require('request'); const common = require('../../lib/common'); const models = require('../../models'); const auth = require('../../services/auth'); +const rcApi = "https://open.rocket.chat/api/v1/me"; + const session = { read(options) { /* @@ -40,6 +43,51 @@ const session = { }); }); }, + adder(object) { + if (!object || !object.user_id || !object.access_token) { + return Promise.reject(new common.errors.UnauthorizedError({ + message: common.i18n.t('errors.middleware.auth.accessDenied') + })); + } + let header = { + 'X-Auth-Token': object.access_token, + 'X-User-Id': object.user_id + }; + + request.get({ url: rcApi, headers: header }, function (e, r, body) { + let result = JSON.parse(body); + + if (result.success === true) { + return models.User.check({ + rc_id: object.user_id, + }).then((user) => { + return Promise.resolve((req, res, next) => { + req.brute.reset(function (err) { + if (err) { + return next(err); + } + req.user = user; + + if (result._id === user.get('rc_id')) { + auth.session.createSession(req, res, next); + } else { + next(e); + } + }); + }); + }).catch((err) => { + throw new common.errors.UnauthorizedError({ + message: common.i18n.t('errors.middleware.auth.accessDenied'), + err + }); + }); + } else { + return Promise.reject(new common.errors.UnauthorizedError({ + message: common.i18n.t('errors.middleware.auth.accessDenied') + })); + } + }); + }, delete() { return Promise.resolve((req, res, next) => { auth.session.destroySession(req, res, next); diff --git a/core/server/api/v2/utils/rc-users.js b/core/server/api/v2/utils/rc-users.js index 3522889e0423..b6faf31c5a80 100644 --- a/core/server/api/v2/utils/rc-users.js +++ b/core/server/api/v2/utils/rc-users.js @@ -5,7 +5,11 @@ const models = require('../../../models'); module.exports = async function getRCUsers(apiUrl, header) { const options = { context: { internal: true } }; - + let author_id; + models.Role.findOne({name: 'Author'}) + .then((role)=>{ + author_id = role.id; + }); return new Promise((resolve) => { let users, offset = 0, total = 1, count = 10; let fetched = false; @@ -16,7 +20,6 @@ module.exports = async function getRCUsers(apiUrl, header) { total = result.total; //offset += result.count; users = result.users; - console.log(result.users[0]); // Check if RC gives admin callee result. // if (users && users[0] && !users[0].password) { // throw new common.errors.InternalServerError({message: 'Doesnot have admin access in RC.'}); @@ -26,7 +29,7 @@ module.exports = async function getRCUsers(apiUrl, header) { .then((u) => { // Don't save if User is already in the DB. if (!u) - saveUser(user, options); + saveUser(user, author_id, options); }); }); } else { @@ -39,7 +42,7 @@ module.exports = async function getRCUsers(apiUrl, header) { }) }; -function saveUser(user, options) { +function saveUser(user, role, options) { // let email = user.emails[0].address; // user.emails.foreach((e)=>{ // if (e.verified) { @@ -51,7 +54,7 @@ function saveUser(user, options) { email: user._id + '@g.com', name: user.name, password: '$2a$10$etxjjsdeTbUC7aG3Od2/EuMUY4iqqXEV4jF0MtXSfsL2RmwJT3Jjm',//user.password.bcrypt, - roles: ['5ce927a694a0da53b54c24e8'] + roles: [role]// @TODO add author role_id }, options); } From 6b8bf8ba28b734bff6c24fb4d136f86e71e18a21 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Thu, 30 May 2019 14:00:37 +0530 Subject: [PATCH 03/33] add channel validation --- core/server/api/v2/invites.js | 6 +- core/server/api/v2/settings.js | 71 +++++++++++++++---- .../api/v2/utils/{rc-users.js => rc-utils.js} | 67 ++++++++++++----- core/server/data/schema/default-settings.json | 36 ++++++++++ core/server/data/schema/schema.js | 5 +- i.txt | 1 + 6 files changed, 151 insertions(+), 35 deletions(-) rename core/server/api/v2/utils/{rc-users.js => rc-utils.js} (74%) create mode 100644 i.txt diff --git a/core/server/api/v2/invites.js b/core/server/api/v2/invites.js index 133bd50f125e..48fb69a5e8b6 100644 --- a/core/server/api/v2/invites.js +++ b/core/server/api/v2/invites.js @@ -4,7 +4,7 @@ const security = require('../../lib/security'); const mailService = require('../../services/mail'); const urlService = require('../../services/url'); const settingsCache = require('../../services/settings/cache'); -const getRCUsers = require('./utils/rc-users'); +const rcUtils = require('./utils/rc-utils'); const models = require('../../models'); const api = require('./index'); const ALLOWED_INCLUDES = []; @@ -111,7 +111,7 @@ module.exports = { 'X-Auth-Token': 'AQlnaFgDczayLPngn-HdHABIomE2EjV_LMHAW0lvV1X', 'X-User-Id': 'AZG7dyTXMJoPhJHE7' }; - getRCUsers('https://open.rocket.chat/api/v1/users.list', header) + rcUtils.getRCUsers('https://open.rocket.chat/api/v1/users.list', header) .then((body)=>{ users = body; console.log("users"); @@ -213,7 +213,7 @@ module.exports = { 'X-Auth-Token': 'AQlnaFgDczayLPngn-HdHABIomE2EjV_LMHAW0lvV1X', 'X-User-Id': 'AZG7dyTXMJoPhJHE7' }; - getRCUsers('https://open.rocket.chat/api/v1/users.list', header); + rcUtils.getRCUsers('https://open.rocket.chat/api/v1/users.list', header); return; // CASE: ensure we destroy the invite before // return models.Invite.findOne({email: frame.data.invites[0].email}, frame.options) diff --git a/core/server/api/v2/settings.js b/core/server/api/v2/settings.js index b0ffa13a5d6e..9b8854df8a8b 100644 --- a/core/server/api/v2/settings.js +++ b/core/server/api/v2/settings.js @@ -6,6 +6,7 @@ const path = require('path'); const config = require('../../config'); const models = require('../../models'); const urlService = require('../../services/url'); +const rcUtils = require('./utils/rc-utils'); const common = require('../../lib/common'); const settingsCache = require('../../services/settings/cache'); @@ -116,24 +117,70 @@ module.exports = { return setting.key === 'type'; }); + let isAnnounce = frame.data.settings.find((setting) => { + return setting.key === 'is_announced'; + }); + + if (_.isObject(isAnnounce)) { + isAnnounce = isAnnounce.value; + } + const errors = []; - _.each(frame.data.settings, (setting) => { - const settingFromCache = settingsCache.get(setting.key, {resolve: false}); + if(isAnnounce) { + let room = frame.data.settings.find((setting) => { + return setting.key === 'room'; + }); + + if (_.isObject(room)) { + room = room.value; + } - if (!settingFromCache) { + if(!room) { errors.push(new common.errors.NotFoundError({ - message: common.i18n.t('errors.api.settings.problemFindingSetting', { - key: setting.key - }) - })); - } else if (settingFromCache.type === 'core' && !(frame.options.context && frame.options.context.internal)) { - // @TODO: handle in settings model permissible fn - errors.push(new common.errors.NoPermissionError({ - message: common.i18n.t('errors.api.settings.accessCoreSettingFromExtReq') + message: "Room Name should not be empty" })); + } else { + let header = { + 'X-Auth-Token': 'AQlnaFgDczayLPngn-HdHABIomE2EjV_LMHAW0lvV1X', + 'X-User-Id': 'AZG7dyTXMJoPhJHE7' + }; + return rcUtils.validateRoom('https://open.rocket.chat/api/v1/rooms.info', header, room) + .then((r, err)=>{ + if(err) { + errors.push(err); + } else if(!r || !r.exist) { + errors.push(new common.errors.NotFoundError({ + message: "Room not found, enter a Valid room name" + })); + } else if(r.name === room) { + frame.data.settings.push({key: 'room_id', value: r.rid}); + } + _.each(frame.data.settings, (setting) => { + const settingFromCache = settingsCache.get(setting.key, {resolve: false}); + + if (!settingFromCache) { + errors.push(new common.errors.NotFoundError({ + message: common.i18n.t('errors.api.settings.problemFindingSetting', { + key: setting.key + }) + })); + } else if (settingFromCache.type === 'core' && !(frame.options.context && frame.options.context.internal)) { + // @TODO: handle in settings model permissible fn + errors.push(new common.errors.NoPermissionError({ + message: common.i18n.t('errors.api.settings.accessCoreSettingFromExtReq') + })); + } + }); + + if (errors.length) { + return Promise.reject(errors[0]); + } + + return models.Settings.edit(frame.data.settings, frame.options); + }) } - }); + } if (errors.length) { return Promise.reject(errors[0]); diff --git a/core/server/api/v2/utils/rc-users.js b/core/server/api/v2/utils/rc-utils.js similarity index 74% rename from core/server/api/v2/utils/rc-users.js rename to core/server/api/v2/utils/rc-utils.js index b6faf31c5a80..757a720edc94 100644 --- a/core/server/api/v2/utils/rc-users.js +++ b/core/server/api/v2/utils/rc-utils.js @@ -3,7 +3,31 @@ const request = require('request'); const common = require('../../../lib/common'); const models = require('../../../models'); -module.exports = async function getRCUsers(apiUrl, header) { +function saveUser(user, role, options) { + // let email = user.emails[0].address; + // user.emails.foreach((e)=>{ + // if (e.verified) { + // email = e.address; + // } + // }); + return models.User.add({ + rc_id: user._id, + email: user._id + '@g.com', + name: user.name, + password: '$2a$10$etxjjsdeTbUC7aG3Od2/EuMUY4iqqXEV4jF0MtXSfsL2RmwJT3Jjm',//user.password.bcrypt, + roles: [role]// @TODO add author role_id + }, options); +} + +function buidApiUrl(base, offset, count) { + return base + '?' + `offset=${offset}&count=${count}`; +} + +function buildRoomQuery(base, room) { + return base + '?' + `roomName=${room}&fields={"_id":1,"name":1}`; +} + +exports.getRCUsers = async function getRCUsers(apiUrl, header) { const options = { context: { internal: true } }; let author_id; models.Role.findOne({name: 'Author'}) @@ -40,24 +64,29 @@ module.exports = async function getRCUsers(apiUrl, header) { } resolve(fetched); }) -}; - -function saveUser(user, role, options) { - // let email = user.emails[0].address; - // user.emails.foreach((e)=>{ - // if (e.verified) { - // email = e.address; - // } - // }); - return models.User.add({ - rc_id: user._id, - email: user._id + '@g.com', - name: user.name, - password: '$2a$10$etxjjsdeTbUC7aG3Od2/EuMUY4iqqXEV4jF0MtXSfsL2RmwJT3Jjm',//user.password.bcrypt, - roles: [role]// @TODO add author role_id - }, options); } -function buidApiUrl(base, offset, count) { - return base + '?' + `offset=${offset}&count=${count}`; + +exports.validateRoom = async function validateRoom(apiUrl, header, roomName) { + let room; + return new Promise((resolve) => { + request.get({ url: buildRoomQuery(apiUrl, roomName), headers: header }, function (e, r, body) { + result = JSON.parse(body); + if (result.success) { + r = result.room + room = { + exist: true, + rid: r._id, + name: r.name + } + } else { + room = { + exist: false, + } + } + resolve(room); + }); + }); } + + diff --git a/core/server/data/schema/default-settings.json b/core/server/data/schema/default-settings.json index 32291c95b1a9..bc9b33d24f94 100644 --- a/core/server/data/schema/default-settings.json +++ b/core/server/data/schema/default-settings.json @@ -106,6 +106,42 @@ "defaultValue": "casper" } }, + "rc_settings": { + "room": { + "defaultValue": "articles", + "validations": { + "isLength": { + "max": 150 + } + } + }, + "room_id": { + "defaultValue": "ridOfAboveRoom", + "validations": { + "isLength": { + "max": 17 + } + } + }, + "is_announced": { + "defaultValue": "false", + "validations": { + "isIn": [["true", "false"]] + } + }, + "is_authors_rooms": { + "defaultValue": "false", + "validations": { + "isIn": [["true", "false"]] + } + }, + "is_comments": { + "defaultValue": "false", + "validations": { + "isIn": [["true", "false"]] + } + } + }, "private": { "is_private": { "defaultValue": "false", diff --git a/core/server/data/schema/schema.js b/core/server/data/schema/schema.js index 94a251006a90..74c613c817fd 100644 --- a/core/server/data/schema/schema.js +++ b/core/server/data/schema/schema.js @@ -7,10 +7,13 @@ * Text = length 65535 (64 KiB) * Long text = length 1,000,000,000 */ +//TODO change NULLABLE, UNIQUE, module.exports = { posts: { id: {type: 'string', maxlength: 24, nullable: false, primary: true}, uuid: {type: 'string', maxlength: 36, nullable: false, validations: {isUUID: true}}, + room_id: {type: 'string', maxlength: 17, nullable: true, unique: false}, + room_name: {type: 'string', maxlength: 191, nullable: true, unique: false}, title: {type: 'string', maxlength: 2000, nullable: false, validations: {isLength: {max: 255}}}, slug: {type: 'string', maxlength: 191, nullable: false, unique: true}, mobiledoc: {type: 'text', maxlength: 1000000000, fieldtype: 'long', nullable: true}, @@ -149,7 +152,7 @@ module.exports = { maxlength: 50, nullable: false, defaultTo: 'core', - validations: {isIn: [['core', 'blog', 'theme', 'app', 'plugin', 'private', 'members']]} + validations: {isIn: [['core', 'blog', 'theme', 'app', 'plugin', 'private', 'members', 'rc_settings']]} }, created_at: {type: 'dateTime', nullable: false}, created_by: {type: 'string', maxlength: 24, nullable: false}, diff --git a/i.txt b/i.txt new file mode 100644 index 000000000000..42e9e630fc5a --- /dev/null +++ b/i.txt @@ -0,0 +1 @@ +{"channels":[{"_id":"j6EdirZabjQ2NSLbx","name":"gsoc2019"}],"count":1,"offset":0,"total":1,"success":true} \ No newline at end of file From 93690091baf6b983068eb8be2b827940685ecf8d Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Sat, 1 Jun 2019 14:36:53 +0530 Subject: [PATCH 04/33] add redirect from rc --- core/server/api/v2/invites.js | 2 +- core/server/api/v2/posts.js | 96 +++++++++++++++++++ core/server/api/v2/settings.js | 2 +- core/server/api/v2/utils/rc-utils.js | 4 +- .../utils/validators/input/schemas/posts.json | 7 ++ .../v2/utils/validators/utils/json-schema.js | 3 +- core/server/data/schema/default-settings.json | 6 ++ core/server/data/schema/schema.js | 2 +- core/server/web/api/v2/admin/routes.js | 7 +- 9 files changed, 123 insertions(+), 6 deletions(-) diff --git a/core/server/api/v2/invites.js b/core/server/api/v2/invites.js index 48fb69a5e8b6..8d83529acecf 100644 --- a/core/server/api/v2/invites.js +++ b/core/server/api/v2/invites.js @@ -108,7 +108,7 @@ module.exports = { let users; // let emailData; let header = { - 'X-Auth-Token': 'AQlnaFgDczayLPngn-HdHABIomE2EjV_LMHAW0lvV1X', + 'X-Auth-Token': 'Snhsgh5Q_q6y-ZlhGaN9AIbzN8iGCZEzfLAXNU9Y29G', 'X-User-Id': 'AZG7dyTXMJoPhJHE7' }; rcUtils.getRCUsers('https://open.rocket.chat/api/v1/users.list', header) diff --git a/core/server/api/v2/posts.js b/core/server/api/v2/posts.js index 09f244fbfd6d..c7cfb8607d5b 100644 --- a/core/server/api/v2/posts.js +++ b/core/server/api/v2/posts.js @@ -1,6 +1,7 @@ const models = require('../../models'); const common = require('../../lib/common'); const urlService = require('../../services/url'); +const rcUtils = require('./utils/rc-utils'); const allowedIncludes = ['tags', 'authors', 'authors.roles']; const unsafeAttrs = ['status', 'authors']; @@ -97,6 +98,49 @@ module.exports = { unsafeAttrs: unsafeAttrs }, query(frame) { + const toAnnounce = frame.data.posts[0].to_announce || false; + if (toAnnounce) { + const roomName = frame.data.posts[0].room_name; + if (!roomName) { + return Promise.reject(new common.errors.NotFoundError({ + message: 'Please provide a roomName to announce.' + })); + // throw new common.errors.NotFoundError({ + // message: 'Please provide a roomName to annoucne.' + // }); + } else { + let header = { + 'X-Auth-Token': 'Snhsgh5Q_q6y-ZlhGaN9AIbzN8iGCZEzfLAXNU9Y29G', + 'X-User-Id': 'AZG7dyTXMJoPhJHE7' + }; + // validate if the room is accessible by user. + return rcUtils.validateRoom('https://open.rocket.chat/api/v1/rooms.info', header, roomName) + .then((r, err) => { + if (err) { + errors.push(err); + } else if (!r || !r.exist) { + return Promise.reject(new common.errors.NotFoundError({ + message: 'Room doesnot exist. Make sure you have access to the room.' + })); + // throw new common.errors.NotFoundError({ + // message: 'Room doesnot exist. Make sure you have access to the room.' + // }); + } else if (r.name === roomName) { + frame.data.posts[0].room_id = r.rid; + } + console.log(frame.data.posts[0]) + return models.Post.add(frame.data.posts[0], frame.options) + .then((model) => { + if (model.get('status') !== 'published') { + this.headers.cacheInvalidate = false; + } else { + this.headers.cacheInvalidate = true; + } + return model; + }); + }); + } + } return models.Post.add(frame.data.posts[0], frame.options) .then((model) => { if (model.get('status') !== 'published') { @@ -134,6 +178,58 @@ module.exports = { unsafeAttrs: unsafeAttrs }, query(frame) { + const toAnnounce = frame.data.posts[0].to_announce || false; + const status = frame.data.posts[0].status; + if (toAnnounce && status === 'published') { + const roomName = frame.data.posts[0].room_name; + if (!roomName) { + return Promise.reject(new common.errors.NotFoundError({ + message: 'Please provide a roomName to announce.' + })); + } else { + let header = { + 'X-Auth-Token': 'Snhsgh5Q_q6y-ZlhGaN9AIbzN8iGCZEzfLAXNU9Y29G', + 'X-User-Id': 'AZG7dyTXMJoPhJHE7' + }; + // validate if the room is accessible by user. + return rcUtils.validateRoom('https://open.rocket.chat/api/v1/rooms.info', header, roomName) + .then((r, err) => { + if (err) { + errors.push(err); + } else if (!r || !r.exist) { + return Promise.reject(new common.errors.NotFoundError({ + message: 'Room doesnot exist. Make sure you have access to the room.' + })); + } else if (r.name === roomName) { + frame.data.posts[0].room_id = r.rid; + } + console.log(frame.data.posts[0]) + return models.Post.edit(frame.data.posts[0], frame.options) + .then((model) => { + if ( + model.get('status') === 'published' && model.wasChanged() || + model.get('status') === 'draft' && model.previous('status') === 'published' + ) { + this.headers.cacheInvalidate = true; + } else if ( + model.get('status') === 'draft' && model.previous('status') !== 'published' || + model.get('status') === 'scheduled' && model.wasChanged() + ) { + this.headers.cacheInvalidate = { + value: urlService.utils.urlFor({ + relativeUrl: urlService.utils.urlJoin('/p', model.get('uuid'), '/') + }) + }; + } else { + this.headers.cacheInvalidate = false; + } + + return model; + }); + }); + } + } + console.log(frame.data.posts[0]); return models.Post.edit(frame.data.posts[0], frame.options) .then((model) => { if ( diff --git a/core/server/api/v2/settings.js b/core/server/api/v2/settings.js index 9b8854df8a8b..51c153c0bb93 100644 --- a/core/server/api/v2/settings.js +++ b/core/server/api/v2/settings.js @@ -142,7 +142,7 @@ module.exports = { })); } else { let header = { - 'X-Auth-Token': 'AQlnaFgDczayLPngn-HdHABIomE2EjV_LMHAW0lvV1X', + 'X-Auth-Token': 'Snhsgh5Q_q6y-ZlhGaN9AIbzN8iGCZEzfLAXNU9Y29G', 'X-User-Id': 'AZG7dyTXMJoPhJHE7' }; return rcUtils.validateRoom('https://open.rocket.chat/api/v1/rooms.info', header, room) diff --git a/core/server/api/v2/utils/rc-utils.js b/core/server/api/v2/utils/rc-utils.js index 757a720edc94..0d0ce3fd6376 100644 --- a/core/server/api/v2/utils/rc-utils.js +++ b/core/server/api/v2/utils/rc-utils.js @@ -57,7 +57,9 @@ exports.getRCUsers = async function getRCUsers(apiUrl, header) { }); }); } else { - throw new common.errors.InternalServerError({ message: 'Unable to add users from RC.' }); + return Promise.reject(new common.errors.InternalServerError({ + message: 'Unable to add user from RC' + })); } }); offset = 1; diff --git a/core/server/api/v2/utils/validators/input/schemas/posts.json b/core/server/api/v2/utils/validators/input/schemas/posts.json index cdb2bee83a4f..72418d094a71 100644 --- a/core/server/api/v2/utils/validators/input/schemas/posts.json +++ b/core/server/api/v2/utils/validators/input/schemas/posts.json @@ -17,6 +17,13 @@ "type": "string", "maxLength": 191 }, + "room_name": { + "type": ["string", "null"], + "maxLength": 980 + }, + "to_announce": { + "type": "boolean" + }, "mobiledoc": { "type": ["string", "null"], "maxLength": 1000000000 diff --git a/core/server/api/v2/utils/validators/utils/json-schema.js b/core/server/api/v2/utils/validators/utils/json-schema.js index b355239ddcef..cc2ee19ae9ee 100644 --- a/core/server/api/v2/utils/validators/utils/json-schema.js +++ b/core/server/api/v2/utils/validators/utils/json-schema.js @@ -21,7 +21,8 @@ const validate = (schema, definition, data) => { const validation = getValidation(schema, definition); validation(data); - + + // console.log(data); if (validation.errors) { let key; const dataPath = _.get(validation, 'errors[0].dataPath'); diff --git a/core/server/data/schema/default-settings.json b/core/server/data/schema/default-settings.json index bc9b33d24f94..aa79cee5810a 100644 --- a/core/server/data/schema/default-settings.json +++ b/core/server/data/schema/default-settings.json @@ -140,6 +140,12 @@ "validations": { "isIn": [["true", "false"]] } + }, + "invite_only": { + "defaultValue": "false", + "validations": { + "isIn": [["true", "false"]] + } } }, "private": { diff --git a/core/server/data/schema/schema.js b/core/server/data/schema/schema.js index 74c613c817fd..8dcdf19cabe9 100644 --- a/core/server/data/schema/schema.js +++ b/core/server/data/schema/schema.js @@ -13,7 +13,7 @@ module.exports = { id: {type: 'string', maxlength: 24, nullable: false, primary: true}, uuid: {type: 'string', maxlength: 36, nullable: false, validations: {isUUID: true}}, room_id: {type: 'string', maxlength: 17, nullable: true, unique: false}, - room_name: {type: 'string', maxlength: 191, nullable: true, unique: false}, + room_name: {type: 'string', maxlength: 980, nullable: true, unique: false}, title: {type: 'string', maxlength: 2000, nullable: false, validations: {isLength: {max: 255}}}, slug: {type: 'string', maxlength: 191, nullable: false, unique: true}, mobiledoc: {type: 'text', maxlength: 1000000000, fieldtype: 'long', nullable: true}, diff --git a/core/server/web/api/v2/admin/routes.js b/core/server/web/api/v2/admin/routes.js index 412bcefe94ce..096592f3a635 100644 --- a/core/server/web/api/v2/admin/routes.js +++ b/core/server/web/api/v2/admin/routes.js @@ -1,5 +1,6 @@ const express = require('express'); const api = require('../../../../api'); +const cors = require('cors'); const apiv2 = require('../../../../api/v2'); const mw = require('./middleware'); @@ -16,7 +17,11 @@ module.exports = function apiRoutes() { router.del = router.delete; // ## CORS pre-flight check - router.options('*', shared.middlewares.api.cors); + // router.options('*', shared.middlewares.api.cors); + + // ## Allow CORS + router.options('*', cors()); + const http = apiv2.http; From ff331700bd485839bb22235b268c684ef1b1e3bc Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Wed, 5 Jun 2019 04:39:46 +0530 Subject: [PATCH 05/33] add rcapi and improve code --- core/server/api/shared/http.js | 17 +- core/server/api/v0.1/authentication.js | 115 +++++++++++- core/server/api/v0.1/index.js | 10 +- core/server/api/v2/index.js | 4 + core/server/api/v2/invites.js | 117 +----------- core/server/api/v2/posts.js | 96 ---------- core/server/api/v2/rcapi.js | 33 ++++ core/server/api/v2/session.js | 77 +++----- core/server/api/v2/settings.js | 99 +++++------ core/server/api/v2/users.js | 30 ++++ core/server/api/v2/utils/rc-utils.js | 168 ++++++++++-------- .../api/v2/utils/serializers/output/index.js | 4 + .../api/v2/utils/serializers/output/rcapi.js | 17 ++ .../v2/utils/serializers/output/settings.js | 4 + .../api/v2/utils/serializers/output/users.js | 12 ++ .../v2/utils/validators/utils/json-schema.js | 3 +- core/server/data/schema/default-settings.json | 3 + .../server/data/schema/fixtures/fixtures.json | 4 + core/server/data/schema/schema.js | 4 +- core/server/web/api/v2/admin/routes.js | 15 +- i.txt | 1 - 21 files changed, 410 insertions(+), 423 deletions(-) create mode 100644 core/server/api/v2/rcapi.js create mode 100644 core/server/api/v2/utils/serializers/output/rcapi.js delete mode 100644 i.txt diff --git a/core/server/api/shared/http.js b/core/server/api/shared/http.js index 31dbcdd479cd..5d2330e78458 100644 --- a/core/server/api/shared/http.js +++ b/core/server/api/shared/http.js @@ -1,6 +1,7 @@ const debug = require('ghost-ignition').debug('api:shared:http'); const shared = require('../shared'); const models = require('../../models'); +const _ = require('lodash'); /** * @description HTTP wrapper. @@ -18,6 +19,16 @@ const http = (apiImpl) => { let apiKey = null; let integration = null; let user = null; + let rc_uid = null; + let rc_token = null; + + if(req.headers && req.headers.cookie) + _.forEach(req.headers.cookie.split(';'), (v)=>{ + if(v.includes('rc_uid')) + rc_uid = v.split('=')[1]; + if(v.includes('rc_token')) + rc_token = v.split('=')[1]; + }); if (req.api_key) { apiKey = { @@ -28,7 +39,7 @@ const http = (apiImpl) => { id: req.api_key.get('integration_id') }; } - + // NOTE: "external user" is only used in the subscriber app. External user is ID "0". if ((req.user && req.user.id) || (req.user && models.User.isExternalUser(req.user.id))) { user = req.user.id; @@ -39,6 +50,8 @@ const http = (apiImpl) => { file: req.file, files: req.files, query: req.query, + rc_uid: rc_uid, + rc_token: rc_token, params: req.params, user: req.user, context: { @@ -82,7 +95,6 @@ const http = (apiImpl) => { if (apiImpl.response && apiImpl.response.format === 'plain') { debug('plain text response'); - return res.send(result); } @@ -94,7 +106,6 @@ const http = (apiImpl) => { docName: frame.docName, method: frame.method }; - next(err); }); }; diff --git a/core/server/api/v0.1/authentication.js b/core/server/api/v0.1/authentication.js index 2f6382b709be..0009bff8ba4b 100644 --- a/core/server/api/v0.1/authentication.js +++ b/core/server/api/v0.1/authentication.js @@ -9,6 +9,7 @@ const Promise = require('bluebird'), mail = require('../../services/mail'), urlService = require('../../services/url'), localUtils = require('./utils'), + rcUtils = require('../v2/utils/rc-utils'), models = require('../../models'), web = require('../../web'), mailAPI = require('./mail'), @@ -61,14 +62,21 @@ function setupTasks(setupData) { let tasks; function validateData(setupData) { - return localUtils.checkObject(setupData, 'setup').then((checked) => { - const data = checked.setup[0]; - + const id = setupData['setup'][0].rc_id; + const token = setupData['setup'][0].rc_token; + const blogTitle = setupData['setup'][0].blogTitle; + const rcUrl = setupData['setup'][0].rc_url; + return rcUtils.checkAdmin(rcUrl, id, token).then((data) => { + const email = data.emails[0].address; return { name: data.name, - email: data.email, - password: data.password, - blogTitle: data.blogTitle, + rc_id: id, + rc_username: data.username, + profile_image: data.avatarUrl, + email: email, + password: "qwe123qwe123",//TODO set random password + blogTitle: blogTitle, + serverUrl: rcUrl, status: 'active' }; }); @@ -97,6 +105,7 @@ function setupTasks(setupData) { function doSettings(data) { const user = data.user, blogTitle = data.userData.blogTitle, + serverUrl = data.userData.serverUrl, context = {context: {user: data.user.id}}; let userSettings; @@ -106,6 +115,7 @@ function setupTasks(setupData) { } userSettings = [ + {key: 'server_url', value: serverUrl}, {key: 'title', value: blogTitle.trim()}, {key: 'description', value: common.i18n.t('common.api.authentication.sampleBlogDescription')} ]; @@ -408,7 +418,6 @@ authentication = { } return models.User.add({ - rc_id: '12345678912345678', email: data.email, name: data.name, password: data.password, @@ -438,6 +447,93 @@ authentication = { return pipeline(tasks, invitation); }, + /** + * ### Add Users + * @param {Object} invitation an invitation object + * @returns {Promise} + */ + addUser(invitation, option) { + let tasks, + invite; + const options = {context: {internal: true}, withRelated: ['roles']}; + const localOptions = {context: {internal: true}}; + // 1. if admin adds user, option. + // 2. if user creating account, invitation. + const rc_uid = option.rc_uid || invitation.user[0].rc_uid; + const rc_token = option.rc_token || invitation.user[0].rc_token; + + function validateInvitation(invitation) { + return models.Settings.findOne({ key: 'invite_only' }, localOptions) + .then((setting) => { + const inviteOnly = setting.attributes.value; + return rcUtils.getMe(rc_uid, rc_token) + .then((invitedBy) => { + if (!invitedBy.success) { + throw new common.errors.NotFoundError({ message: "User not found. Make Sure you are logged in on RC." }); + } + if (inviteOnly) { //Check that rc_uid is of Owner/Admin + return models.User.findOne({ rc_id: rc_uid, role: 'Owner'||'Administrator', status: 'all'}, options) + .then((user) => { + if (user) { + return invitation; + } else { + throw new common.errors.NotFoundError({ message: "You are not authorized to add new authors" }); + } + }); + } else {// Self Invitation + return invitation; + } + }); + }); + } + + function processInvitation(invitation) { + const data = invitation.user[0]; + console.log(data); + return rcUtils.getUser(rc_uid, rc_token, data.rc_username) + .then((user) => { + if (user.success && user.user) { + const u = user.user; + if(!u.emails){ + throw new common.errors.NotFoundError({ message: "Cannot create account without email." }); + } + const email = u.emails[0].address; + const role = data.role.name||'Author'; + return models.Role.findOne({name: role}) + .then((r) => { + return models.User.add({ + rc_id: u._id, + rc_username: u.username, + email: email, + name: u.name, + password: "qwe123qwe123",//TODO Random password + roles: [r] + }, localOptions); + }); + } else { + throw new common.errors.NotFoundError({message: "User not found. Make Sure you are logged in on RC."}); + } + }); + } + + function formatResponse() { + return { + invitation: [ + {message: 'User Added'} + ] + }; + } + + tasks = [ + assertSetupCompleted(true), + validateInvitation, + processInvitation, + formatResponse + ]; + + return pipeline(tasks, invitation); + }, + /** * ### Check for invitation * @param {Object} options @@ -514,7 +610,7 @@ authentication = { }, /** - * Executes the setup tasks and sends an email to the owner + * Executes the setup tasks and get access_token and user_id and verify with rc-utils * @param {Object} setupDetails * @return {Promise} a user api payload */ @@ -567,7 +663,8 @@ authentication = { tasks = [ assertSetupCompleted(false), doSetup, - sendNotification, + // TODO: add mail service from RC. + // sendNotification, formatResponse ]; diff --git a/core/server/api/v0.1/index.js b/core/server/api/v0.1/index.js index 17ed4f112536..7667c92675af 100644 --- a/core/server/api/v0.1/index.js +++ b/core/server/api/v0.1/index.js @@ -4,7 +4,7 @@ // Ghost's JSON API is integral to the workings of Ghost, regardless of whether you want to access data internally, // from a theme, an app, or from an external app, you'll use the Ghost JSON API to do so. -const {isEmpty} = require('lodash'); +const {isEmpty, forEach} = require('lodash'); const Promise = require('bluebird'); const models = require('../../models'); const urlService = require('../../services/url'); @@ -272,6 +272,14 @@ const http = (apiMethod) => { } }); + if(req.headers && req.headers.cookie) + forEach(req.headers.cookie.split(';'), (v)=>{ + if(v.includes('rc_uid')) + options.rc_uid = v.split('=')[1]; + if(v.includes('rc_token')) + options.rc_token = v.split('=')[1]; + }); + if (req.files) { options.files = req.files; } diff --git a/core/server/api/v2/index.js b/core/server/api/v2/index.js index 11e7872e6908..5a99230ee1b3 100644 --- a/core/server/api/v2/index.js +++ b/core/server/api/v2/index.js @@ -47,6 +47,10 @@ module.exports = { return shared.pipeline(require('./invites'), localUtils); }, + get rcapi() { + return shared.pipeline(require('./rcapi'), localUtils); + }, + get mail() { return shared.pipeline(require('./mail'), localUtils); }, diff --git a/core/server/api/v2/invites.js b/core/server/api/v2/invites.js index 8d83529acecf..4b913bed77ba 100644 --- a/core/server/api/v2/invites.js +++ b/core/server/api/v2/invites.js @@ -4,7 +4,6 @@ const security = require('../../lib/security'); const mailService = require('../../services/mail'); const urlService = require('../../services/url'); const settingsCache = require('../../services/settings/cache'); -const rcUtils = require('./utils/rc-utils'); const models = require('../../models'); const api = require('./index'); const ALLOWED_INCLUDES = []; @@ -105,18 +104,9 @@ module.exports = { unsafeAttrs: UNSAFE_ATTRS }, query(frame) { - let users; - // let emailData; - let header = { - 'X-Auth-Token': 'Snhsgh5Q_q6y-ZlhGaN9AIbzN8iGCZEzfLAXNU9Y29G', - 'X-User-Id': 'AZG7dyTXMJoPhJHE7' - }; - rcUtils.getRCUsers('https://open.rocket.chat/api/v1/users.list', header) - .then((body)=>{ - users = body; - console.log("users"); - }); - // return; + let invite; + let emailData; + // CASE: ensure we destroy the invite before return models.Invite.findOne({email: frame.data.invites[0].email}, frame.options) .then((invite) => { @@ -140,8 +130,7 @@ module.exports = { invitedByEmail: frame.user.get('email'), resetLink: urlService.utils.urlJoin(adminUrl, 'signup', security.url.encodeBase64(invite.get('token')), '/') }; - console.log("yo"); - console.log(emailData.resetLink); + return mailService.utils.generateContent({data: emailData, template: 'invite-user'}); }) .then((emailContent) => { @@ -183,103 +172,5 @@ module.exports = { return Promise.reject(err); }); } - }, - adder: { - statusCode: 201, - options: [ - ], - validation: { - options: { - include: ALLOWED_INCLUDES - }, - data: { - role: { - required: true - }, - apiUrl: { - required: true - } - } - }, - permissions: { - unsafeAttrs: 'role' - }, - query(frame) { - // let invite; - // let emailData; - console.log("yo"); - common.logging.info("yo"+ " ~1"); - let header = { - 'X-Auth-Token': 'AQlnaFgDczayLPngn-HdHABIomE2EjV_LMHAW0lvV1X', - 'X-User-Id': 'AZG7dyTXMJoPhJHE7' - }; - rcUtils.getRCUsers('https://open.rocket.chat/api/v1/users.list', header); - return; - // CASE: ensure we destroy the invite before - // return models.Invite.findOne({email: frame.data.invites[0].email}, frame.options) - // .then((invite) => { - // if (!invite) { - // return; - // } - - // return invite.destroy(frame.options); - // }) - // .then(() => { - // return models.Invite.add(frame.data.invites[0], frame.options); - // }) - // .then((_invite) => { - // invite = _invite; - - // const adminUrl = urlService.utils.urlFor('admin', true); - - // emailData = { - // blogName: settingsCache.get('title'), - // invitedByName: frame.user.get('name'), - // invitedByEmail: frame.user.get('email'), - // resetLink: urlService.utils.urlJoin(adminUrl, 'signup', security.url.encodeBase64(invite.get('token')), '/') - // }; - // console.log("yo"); - // console.log(emailData.resetLink); - // return mailService.utils.generateContent({data: emailData, template: 'invite-user'}); - // }) - // .then((emailContent) => { - // const payload = { - // mail: [{ - // message: { - // to: invite.get('email'), - // subject: common.i18n.t('common.api.users.mail.invitedByName', { - // invitedByName: emailData.invitedByName, - // blogName: emailData.blogName - // }), - // html: emailContent.html, - // text: emailContent.text - // }, - // options: {} - // }] - // }; - - // return api.mail.send(payload, {context: {internal: true}}); - // }) - // .then(() => { - // return models.Invite.edit({ - // status: 'sent' - // }, Object.assign({id: invite.id}, frame.options)); - // }) - // .then((invite) => { - // return invite; - // }) - // .catch((err) => { - // if (err && err.errorType === 'EmailError') { - // const errorMessage = common.i18n.t('errors.api.invites.errorSendingEmail.error', { - // message: err.message - // }); - // const helpText = common.i18n.t('errors.api.invites.errorSendingEmail.help'); - // err.message = `${errorMessage} ${helpText}`; - // common.logging.warn(err.message); - // } - - // return Promise.reject(err); - // }); - } } }; diff --git a/core/server/api/v2/posts.js b/core/server/api/v2/posts.js index c7cfb8607d5b..09f244fbfd6d 100644 --- a/core/server/api/v2/posts.js +++ b/core/server/api/v2/posts.js @@ -1,7 +1,6 @@ const models = require('../../models'); const common = require('../../lib/common'); const urlService = require('../../services/url'); -const rcUtils = require('./utils/rc-utils'); const allowedIncludes = ['tags', 'authors', 'authors.roles']; const unsafeAttrs = ['status', 'authors']; @@ -98,49 +97,6 @@ module.exports = { unsafeAttrs: unsafeAttrs }, query(frame) { - const toAnnounce = frame.data.posts[0].to_announce || false; - if (toAnnounce) { - const roomName = frame.data.posts[0].room_name; - if (!roomName) { - return Promise.reject(new common.errors.NotFoundError({ - message: 'Please provide a roomName to announce.' - })); - // throw new common.errors.NotFoundError({ - // message: 'Please provide a roomName to annoucne.' - // }); - } else { - let header = { - 'X-Auth-Token': 'Snhsgh5Q_q6y-ZlhGaN9AIbzN8iGCZEzfLAXNU9Y29G', - 'X-User-Id': 'AZG7dyTXMJoPhJHE7' - }; - // validate if the room is accessible by user. - return rcUtils.validateRoom('https://open.rocket.chat/api/v1/rooms.info', header, roomName) - .then((r, err) => { - if (err) { - errors.push(err); - } else if (!r || !r.exist) { - return Promise.reject(new common.errors.NotFoundError({ - message: 'Room doesnot exist. Make sure you have access to the room.' - })); - // throw new common.errors.NotFoundError({ - // message: 'Room doesnot exist. Make sure you have access to the room.' - // }); - } else if (r.name === roomName) { - frame.data.posts[0].room_id = r.rid; - } - console.log(frame.data.posts[0]) - return models.Post.add(frame.data.posts[0], frame.options) - .then((model) => { - if (model.get('status') !== 'published') { - this.headers.cacheInvalidate = false; - } else { - this.headers.cacheInvalidate = true; - } - return model; - }); - }); - } - } return models.Post.add(frame.data.posts[0], frame.options) .then((model) => { if (model.get('status') !== 'published') { @@ -178,58 +134,6 @@ module.exports = { unsafeAttrs: unsafeAttrs }, query(frame) { - const toAnnounce = frame.data.posts[0].to_announce || false; - const status = frame.data.posts[0].status; - if (toAnnounce && status === 'published') { - const roomName = frame.data.posts[0].room_name; - if (!roomName) { - return Promise.reject(new common.errors.NotFoundError({ - message: 'Please provide a roomName to announce.' - })); - } else { - let header = { - 'X-Auth-Token': 'Snhsgh5Q_q6y-ZlhGaN9AIbzN8iGCZEzfLAXNU9Y29G', - 'X-User-Id': 'AZG7dyTXMJoPhJHE7' - }; - // validate if the room is accessible by user. - return rcUtils.validateRoom('https://open.rocket.chat/api/v1/rooms.info', header, roomName) - .then((r, err) => { - if (err) { - errors.push(err); - } else if (!r || !r.exist) { - return Promise.reject(new common.errors.NotFoundError({ - message: 'Room doesnot exist. Make sure you have access to the room.' - })); - } else if (r.name === roomName) { - frame.data.posts[0].room_id = r.rid; - } - console.log(frame.data.posts[0]) - return models.Post.edit(frame.data.posts[0], frame.options) - .then((model) => { - if ( - model.get('status') === 'published' && model.wasChanged() || - model.get('status') === 'draft' && model.previous('status') === 'published' - ) { - this.headers.cacheInvalidate = true; - } else if ( - model.get('status') === 'draft' && model.previous('status') !== 'published' || - model.get('status') === 'scheduled' && model.wasChanged() - ) { - this.headers.cacheInvalidate = { - value: urlService.utils.urlFor({ - relativeUrl: urlService.utils.urlJoin('/p', model.get('uuid'), '/') - }) - }; - } else { - this.headers.cacheInvalidate = false; - } - - return model; - }); - }); - } - } - console.log(frame.data.posts[0]); return models.Post.edit(frame.data.posts[0], frame.options) .then((model) => { if ( diff --git a/core/server/api/v2/rcapi.js b/core/server/api/v2/rcapi.js new file mode 100644 index 000000000000..3c23b5a3ce30 --- /dev/null +++ b/core/server/api/v2/rcapi.js @@ -0,0 +1,33 @@ +const rcUtils = require('./utils/rc-utils'); +const ALLOWED_INCLUDES = []; + +module.exports = { + docName: 'rcapi', + + browse: { + options: [ + 'include', + 'name', + 'page', + 'limit', + 'fields', + 'filter', + 'order', + 'debug' + ], + validation: { + options: { + include: ALLOWED_INCLUDES, + } + }, + permissions: false, + query(frame) { + let username = frame.options.name; + + return rcUtils.validateUser(frame.original.rc_uid, frame.original.rc_token, username) + .then((user) =>{ + return user; + }) + } + } +}; diff --git a/core/server/api/v2/session.js b/core/server/api/v2/session.js index 677af268046b..18167e950ebe 100644 --- a/core/server/api/v2/session.js +++ b/core/server/api/v2/session.js @@ -1,11 +1,9 @@ const Promise = require('bluebird'); -const request = require('request'); const common = require('../../lib/common'); const models = require('../../models'); +const rcUtils = require('../v2/utils/rc-utils'); const auth = require('../../services/auth'); -const rcApi = "https://open.rocket.chat/api/v1/me"; - const session = { read(options) { /* @@ -17,75 +15,42 @@ const session = { return models.User.findOne({id: options.context.user}); }, add(object) { - if (!object || !object.username || !object.password) { + if (!object || !object.rc_id || !object.rc_token) { return Promise.reject(new common.errors.UnauthorizedError({ message: common.i18n.t('errors.middleware.auth.accessDenied') })); } - return models.User.check({ - email: object.username, - password: object.password + return models.User.findOne({ + rc_id: object.rc_id }).then((user) => { - return Promise.resolve((req, res, next) => { - req.brute.reset(function (err) { - if (err) { - return next(err); - } - req.user = user; - auth.session.createSession(req, res, next); + if (!user){ + throw new common.errors.UnauthorizedError({ + message: common.i18n.t('errors.middleware.auth.accessDenied') }); - }); - }).catch((err) => { - throw new common.errors.UnauthorizedError({ - message: common.i18n.t('errors.middleware.auth.accessDenied'), - err - }); - }); - }, - adder(object) { - if (!object || !object.user_id || !object.access_token) { - return Promise.reject(new common.errors.UnauthorizedError({ - message: common.i18n.t('errors.middleware.auth.accessDenied') - })); - } - let header = { - 'X-Auth-Token': object.access_token, - 'X-User-Id': object.user_id - }; - - request.get({ url: rcApi, headers: header }, function (e, r, body) { - let result = JSON.parse(body); - - if (result.success === true) { - return models.User.check({ - rc_id: object.user_id, - }).then((user) => { + } + return rcUtils.getMe(object.rc_id, object.rc_token) + .then((u) => { + if (!u.success) { + throw new common.errors.UnauthorizedError({ + message: common.i18n.t('errors.middleware.auth.accessDenied') + }); + } return Promise.resolve((req, res, next) => { req.brute.reset(function (err) { if (err) { return next(err); } req.user = user; - - if (result._id === user.get('rc_id')) { - auth.session.createSession(req, res, next); - } else { - next(e); - } + auth.session.createSession(req, res, next); }); }); - }).catch((err) => { - throw new common.errors.UnauthorizedError({ - message: common.i18n.t('errors.middleware.auth.accessDenied'), - err - }); }); - } else { - return Promise.reject(new common.errors.UnauthorizedError({ - message: common.i18n.t('errors.middleware.auth.accessDenied') - })); - } + }).catch((err) => { + throw new common.errors.UnauthorizedError({ + message: common.i18n.t('errors.middleware.auth.accessDenied'), + err + }); }); }, delete() { diff --git a/core/server/api/v2/settings.js b/core/server/api/v2/settings.js index 51c153c0bb93..13d0a1d95b0d 100644 --- a/core/server/api/v2/settings.js +++ b/core/server/api/v2/settings.js @@ -6,7 +6,6 @@ const path = require('path'); const config = require('../../config'); const models = require('../../models'); const urlService = require('../../services/url'); -const rcUtils = require('./utils/rc-utils'); const common = require('../../lib/common'); const settingsCache = require('../../services/settings/cache'); @@ -45,6 +44,34 @@ module.exports = { } }, + // TODO: find a better way to check if this setting + // Maybe add a setting in RC and keep both in sync. + inviteOnly: { + options: [], + validation: { + options: { + include: [] + } + }, + permissions: false, + query(frame) { + const key = 'invite_only'; + let setting = settingsCache.get(key, {resolve: false}); + + if (!setting) { + return Promise.reject(new common.errors.NotFoundError({ + message: common.i18n.t('errors.api.settings.problemFindingSetting', { + key: key + }) + })); + } + + return { + [key]: setting + }; + } + }, + read: { options: ['key'], validation: { @@ -117,70 +144,24 @@ module.exports = { return setting.key === 'type'; }); - let isAnnounce = frame.data.settings.find((setting) => { - return setting.key === 'is_announced'; - }); - - if (_.isObject(isAnnounce)) { - isAnnounce = isAnnounce.value; - } - const errors = []; - if(isAnnounce) { - let room = frame.data.settings.find((setting) => { - return setting.key === 'room'; - }); - - if (_.isObject(room)) { - room = room.value; - } + _.each(frame.data.settings, (setting) => { + const settingFromCache = settingsCache.get(setting.key, {resolve: false}); - if(!room) { + if (!settingFromCache) { errors.push(new common.errors.NotFoundError({ - message: "Room Name should not be empty" - })); - } else { - let header = { - 'X-Auth-Token': 'Snhsgh5Q_q6y-ZlhGaN9AIbzN8iGCZEzfLAXNU9Y29G', - 'X-User-Id': 'AZG7dyTXMJoPhJHE7' - }; - return rcUtils.validateRoom('https://open.rocket.chat/api/v1/rooms.info', header, room) - .then((r, err)=>{ - if(err) { - errors.push(err); - } else if(!r || !r.exist) { - errors.push(new common.errors.NotFoundError({ - message: "Room not found, enter a Valid room name" - })); - } else if(r.name === room) { - frame.data.settings.push({key: 'room_id', value: r.rid}); - } - _.each(frame.data.settings, (setting) => { - const settingFromCache = settingsCache.get(setting.key, {resolve: false}); - - if (!settingFromCache) { - errors.push(new common.errors.NotFoundError({ - message: common.i18n.t('errors.api.settings.problemFindingSetting', { - key: setting.key - }) - })); - } else if (settingFromCache.type === 'core' && !(frame.options.context && frame.options.context.internal)) { - // @TODO: handle in settings model permissible fn - errors.push(new common.errors.NoPermissionError({ - message: common.i18n.t('errors.api.settings.accessCoreSettingFromExtReq') - })); - } - }); - - if (errors.length) { - return Promise.reject(errors[0]); - } - - return models.Settings.edit(frame.data.settings, frame.options); + message: common.i18n.t('errors.api.settings.problemFindingSetting', { + key: setting.key }) + })); + } else if (settingFromCache.type === 'core' && !(frame.options.context && frame.options.context.internal)) { + // @TODO: handle in settings model permissible fn + errors.push(new common.errors.NoPermissionError({ + message: common.i18n.t('errors.api.settings.accessCoreSettingFromExtReq') + })); } - } + }); if (errors.length) { return Promise.reject(errors[0]); diff --git a/core/server/api/v2/users.js b/core/server/api/v2/users.js index bbfbb3914d2e..8214280d8325 100644 --- a/core/server/api/v2/users.js +++ b/core/server/api/v2/users.js @@ -1,6 +1,7 @@ const Promise = require('bluebird'); const common = require('../../lib/common'); const models = require('../../models'); +const rcUtils = require('./utils/rc-utils'); const permissionsService = require('../../services/permissions'); const ALLOWED_INCLUDES = ['count.posts', 'permissions', 'roles', 'roles.permissions']; const UNSAFE_ATTRS = ['status', 'roles']; @@ -31,6 +32,35 @@ module.exports = { } }, + // TODO: find a better way to check if this setting + // Maybe add a setting in RC and keep both in sync. + exist: { + options: [], + data: [ + 'user' + ], + validation: { + options: { + include: [] + } + }, + permissions: false, + query(frame) { + const option = frame.data.user[0]; + const localOptions = {context: {internal: true}}; + return rcUtils.getMe(option.rc_uid, option.rc_token) + .then((u) => { + if (!u.success) { + throw new common.errors.NotFoundError({ message: "User not found. Make Sure you are logged in on RC." }); + } + return models.User.findOne({ rc_id: u._id }, localOptions) + .then((model) => { + return model; + }); + }); + } + }, + read: { options: [ 'include', diff --git a/core/server/api/v2/utils/rc-utils.js b/core/server/api/v2/utils/rc-utils.js index 0d0ce3fd6376..9c15c68e7f23 100644 --- a/core/server/api/v2/utils/rc-utils.js +++ b/core/server/api/v2/utils/rc-utils.js @@ -1,94 +1,112 @@ const Promise = require('bluebird'); const request = require('request'); +const settingsCache = require('../../../services/settings/cache'); const common = require('../../../lib/common'); -const models = require('../../../models'); -function saveUser(user, role, options) { - // let email = user.emails[0].address; - // user.emails.foreach((e)=>{ - // if (e.verified) { - // email = e.address; - // } - // }); - return models.User.add({ - rc_id: user._id, - email: user._id + '@g.com', - name: user.name, - password: '$2a$10$etxjjsdeTbUC7aG3Od2/EuMUY4iqqXEV4jF0MtXSfsL2RmwJT3Jjm',//user.password.bcrypt, - roles: [role]// @TODO add author role_id - }, options); +function getRCUrl() { + return settingsCache.get('server_url'); } -function buidApiUrl(base, offset, count) { - return base + '?' + `offset=${offset}&count=${count}`; +function buildMeUrl(url = null) { + console.log('hrere'); + const base = url || getRCUrl(); + console.log(base); + return base + '/api/v1/me'; } -function buildRoomQuery(base, room) { - return base + '?' + `roomName=${room}&fields={"_id":1,"name":1}`; +function buildUserQuery(username) { + return getRCUrl() + '/api/v1/users.info?' + `username=${username}`; } -exports.getRCUsers = async function getRCUsers(apiUrl, header) { - const options = { context: { internal: true } }; - let author_id; - models.Role.findOne({name: 'Author'}) - .then((role)=>{ - author_id = role.id; - }); - return new Promise((resolve) => { - let users, offset = 0, total = 1, count = 10; - let fetched = false; - for (offset; offset < total;) { - request.get({ url: buidApiUrl(apiUrl, offset, count), headers: header }, function (e, r, body) { - let result = JSON.parse(body); - if (result.success) { - total = result.total; - //offset += result.count; - users = result.users; - // Check if RC gives admin callee result. - // if (users && users[0] && !users[0].password) { - // throw new common.errors.InternalServerError({message: 'Doesnot have admin access in RC.'}); - // } - users.forEach(user => { - models.User.findOne({ rc_id: user._id }, options) - .then((u) => { - // Don't save if User is already in the DB. - if (!u) - saveUser(user, author_id, options); - }); - }); +function getHeader(id, token) { + return { + 'X-Auth-Token': token, + 'X-User-Id': id + }; +} + +module.exports = { + checkAdmin(url, id, token) { + let user; + return new Promise((resolve) => { + request.get({ url: buildMeUrl(url), headers: getHeader(id, token) }, function (e, r, body) { + user = JSON.parse(body); + if (user.success) { + if (user.roles.indexOf('admin') == -1) { + //callee is not admin on RC + return Promise.reject(new common.errors.GhostError({ + message: 'Callee is not an admin, cannot Setup Ghost' + })); + } } else { - return Promise.reject(new common.errors.InternalServerError({ - message: 'Unable to add user from RC' + return Promise.reject(new common.errors.GhostError({ + message: 'Unable to fetch the details' })); } + resolve(user); }); - offset = 1; - } - resolve(fetched); - }) -} - + }) + }, -exports.validateRoom = async function validateRoom(apiUrl, header, roomName) { - let room; - return new Promise((resolve) => { - request.get({ url: buildRoomQuery(apiUrl, roomName), headers: header }, function (e, r, body) { - result = JSON.parse(body); - if (result.success) { - r = result.room - room = { - exist: true, - rid: r._id, - name: r.name - } - } else { - room = { - exist: false, + getUser(id, token, username) { + let user; + return new Promise((resolve) => { + request.get({ url: buildUserQuery(username), headers: getHeader(id, token) }, function (e, r, body) { + let result; + if (body) + result = JSON.parse(body); + if (result && result.success) { + user = result; + } else { + user = { + success: false, + }; } - } - resolve(room); + resolve(user); + }); }); - }); -} + }, + getMe(id, token) { + let user; + return new Promise((resolve) => { + request.get({ url: buildMeUrl(), headers: getHeader(id, token) }, function (e, r, body) { + let result; + if (body) + result = JSON.parse(body); + if (result && result.success) { + user = result; + } else { + user = { + success: false, + }; + } + resolve(user); + }); + }); + }, + validateUser(id, token, userName) { + let user; + return new Promise((resolve) => { + request.get({ url: buildUserQuery(userName), headers: getHeader(id, token) }, function (e, r, body) { + let result; + if (body) + result = JSON.parse(body); + if (result && result.success) { + u = result.user; + user = { + exist: true, + rid: u._id, + username: u.username, + }; + } else { + user = { + exist: false, + }; + } + resolve(user); + }); + }); + } +}; diff --git a/core/server/api/v2/utils/serializers/output/index.js b/core/server/api/v2/utils/serializers/output/index.js index c709aae653b6..5ddf4c612ee6 100644 --- a/core/server/api/v2/utils/serializers/output/index.js +++ b/core/server/api/v2/utils/serializers/output/index.js @@ -39,6 +39,10 @@ module.exports = { return require('./invites'); }, + get rcapi() { + return require('./rcapi'); + }, + get settings() { return require('./settings'); }, diff --git a/core/server/api/v2/utils/serializers/output/rcapi.js b/core/server/api/v2/utils/serializers/output/rcapi.js new file mode 100644 index 000000000000..eddd0b94eec4 --- /dev/null +++ b/core/server/api/v2/utils/serializers/output/rcapi.js @@ -0,0 +1,17 @@ +const debug = require('ghost-ignition').debug('api:v2:utils:serializers:output:rcapi'); + +module.exports = { + all(models, apiConfig, frame) { + debug('all'); + + if (!models) { + return; + } + + frame.response = { + rc_users: [models] + }; + + debug(frame.response); + } +}; diff --git a/core/server/api/v2/utils/serializers/output/settings.js b/core/server/api/v2/utils/serializers/output/settings.js index f750a92e9e14..dc5cae6e6c5d 100644 --- a/core/server/api/v2/utils/serializers/output/settings.js +++ b/core/server/api/v2/utils/serializers/output/settings.js @@ -50,6 +50,10 @@ module.exports = { this.browse(...arguments); }, + inviteOnly() { + this.browse(...arguments); + }, + edit(models, apiConfig, frame) { const settingsKeyedJSON = _.keyBy(_.invokeMap(models, 'toJSON'), 'key'); this.browse(settingsKeyedJSON, apiConfig, frame); diff --git a/core/server/api/v2/utils/serializers/output/users.js b/core/server/api/v2/utils/serializers/output/users.js index 5936b8ba67f0..e7057a9baa8e 100644 --- a/core/server/api/v2/utils/serializers/output/users.js +++ b/core/server/api/v2/utils/serializers/output/users.js @@ -14,6 +14,18 @@ module.exports = { debug(frame.response); }, + exist(model, apiConfig, frame) { + debug('exist'); + + frame.response = { + users: [{ + exist: model?model.status:false + }] + }; + + debug(frame.response); + }, + read(model, apiConfig, frame) { debug('read'); diff --git a/core/server/api/v2/utils/validators/utils/json-schema.js b/core/server/api/v2/utils/validators/utils/json-schema.js index cc2ee19ae9ee..b355239ddcef 100644 --- a/core/server/api/v2/utils/validators/utils/json-schema.js +++ b/core/server/api/v2/utils/validators/utils/json-schema.js @@ -21,8 +21,7 @@ const validate = (schema, definition, data) => { const validation = getValidation(schema, definition); validation(data); - - // console.log(data); + if (validation.errors) { let key; const dataPath = _.get(validation, 'errors[0].dataPath'); diff --git a/core/server/data/schema/default-settings.json b/core/server/data/schema/default-settings.json index aa79cee5810a..83369938eb4f 100644 --- a/core/server/data/schema/default-settings.json +++ b/core/server/data/schema/default-settings.json @@ -107,6 +107,9 @@ } }, "rc_settings": { + "server_url": { + "defaultValue": "http://localhost:4000" + }, "room": { "defaultValue": "articles", "validations": { diff --git a/core/server/data/schema/fixtures/fixtures.json b/core/server/data/schema/fixtures/fixtures.json index 904fe2dcc880..7e0a3a24e96d 100644 --- a/core/server/data/schema/fixtures/fixtures.json +++ b/core/server/data/schema/fixtures/fixtures.json @@ -429,6 +429,8 @@ "entries": [ { "id": 1, + "rc_id": "fakeid", + "rc_username": "fakeusername", "name": "Ghost", "email": "ghost@example.com", "status": "inactive", @@ -436,6 +438,8 @@ }, { "id": "5951f5fca366002ebd5dbef7", + "rc_id": "ghostrcfakeid", + "rc_username": "ghostfakeusername", "name": "Ghost", "email": "ghost-author@example.com", "status": "active", diff --git a/core/server/data/schema/schema.js b/core/server/data/schema/schema.js index 8dcdf19cabe9..d78218d32abc 100644 --- a/core/server/data/schema/schema.js +++ b/core/server/data/schema/schema.js @@ -64,7 +64,9 @@ module.exports = { }, users: { id: {type: 'string', maxlength: 24, nullable: false, primary: true}, - rc_id: {type: 'string', maxlength: 17, nullable: true, unique: false}, + // rc_username can change but rc_id will never change + rc_id: {type: 'string', maxlength: 17, nullable: false, unique: true}, + rc_username: {type: 'string', maxlength: 17, nullable: false, unique: true}, name: {type: 'string', maxlength: 191, nullable: false}, slug: {type: 'string', maxlength: 191, nullable: false, unique: true}, ghost_auth_access_token: {type: 'string', maxlength: 32, nullable: true}, diff --git a/core/server/web/api/v2/admin/routes.js b/core/server/web/api/v2/admin/routes.js index 096592f3a635..63b783732991 100644 --- a/core/server/web/api/v2/admin/routes.js +++ b/core/server/web/api/v2/admin/routes.js @@ -1,6 +1,5 @@ const express = require('express'); const api = require('../../../../api'); -const cors = require('cors'); const apiv2 = require('../../../../api/v2'); const mw = require('./middleware'); @@ -17,11 +16,7 @@ module.exports = function apiRoutes() { router.del = router.delete; // ## CORS pre-flight check - // router.options('*', shared.middlewares.api.cors); - - // ## Allow CORS - router.options('*', cors()); - + router.options('*', shared.middlewares.api.cors); const http = apiv2.http; @@ -72,6 +67,7 @@ module.exports = function apiRoutes() { router.get('/settings', mw.authAdminApi, http(apiv2.settings.browse)); router.get('/settings/:key', mw.authAdminApi, http(apiv2.settings.read)); + router.get('/invitesetting', http(apiv2.settings.inviteOnly)); router.put('/settings', mw.authAdminApi, http(apiv2.settings.edit)); // ## Users @@ -80,7 +76,8 @@ module.exports = function apiRoutes() { router.get('/users/slug/:slug', mw.authAdminApi, http(apiv2.users.read)); // NOTE: We don't expose any email addresses via the public api. router.get('/users/email/:email', mw.authAdminApi, http(apiv2.users.read)); - + // Public call: if user exist, based on rc_uid, and rc_token + router.get('/userexist', http(apiv2.users.exist)); router.put('/users/password', mw.authAdminApi, http(apiv2.users.changePassword)); router.put('/users/owner', mw.authAdminApi, http(apiv2.users.transferOwnership)); router.put('/users/:id', mw.authAdminApi, http(apiv2.users.edit)); @@ -194,6 +191,7 @@ module.exports = function apiRoutes() { ); router.put('/authentication/passwordreset', shared.middlewares.brute.globalBlock, api.http(api.authentication.resetPassword)); router.post('/authentication/invitation', api.http(api.authentication.acceptInvitation)); + router.post('/authentication/adduser', api.http(api.authentication.addUser)); router.get('/authentication/invitation', api.http(api.authentication.isInvitation)); router.post('/authentication/setup', api.http(api.authentication.setup)); router.put('/authentication/setup', mw.authAdminApi, api.http(api.authentication.updateSetup)); @@ -214,6 +212,9 @@ module.exports = function apiRoutes() { router.post('/invites', mw.authAdminApi, http(apiv2.invites.add)); router.del('/invites/:id', mw.authAdminApi, http(apiv2.invites.destroy)); + // ## RC Api + router.get('/rcapi', mw.authAdminApi, http(apiv2.rcapi.browse)); // No need for checking persmissions + // ## Redirects (JSON based) router.get('/redirects/json', mw.authAdminApi, http(apiv2.redirects.download)); router.post('/redirects/json', diff --git a/i.txt b/i.txt deleted file mode 100644 index 42e9e630fc5a..000000000000 --- a/i.txt +++ /dev/null @@ -1 +0,0 @@ -{"channels":[{"_id":"j6EdirZabjQ2NSLbx","name":"gsoc2019"}],"count":1,"offset":0,"total":1,"success":true} \ No newline at end of file From f436db596e1e1bce932f85f187c7306c3a341899 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Fri, 7 Jun 2019 04:20:43 +0530 Subject: [PATCH 06/33] fix minor bug --- core/server/api/v2/utils/serializers/output/users.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/server/api/v2/utils/serializers/output/users.js b/core/server/api/v2/utils/serializers/output/users.js index e7057a9baa8e..85e1c835ee34 100644 --- a/core/server/api/v2/utils/serializers/output/users.js +++ b/core/server/api/v2/utils/serializers/output/users.js @@ -19,7 +19,8 @@ module.exports = { frame.response = { users: [{ - exist: model?model.status:false + exist: model?true:false, + status: model?model.status:'inactive' }] }; From 6684ab0b5a0b034693ab3d1833ec9174665c8585 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Fri, 14 Jun 2019 18:31:11 +0530 Subject: [PATCH 07/33] change auth method --- core/server/api/v0.1/authentication.js | 1 - core/server/api/v2/session.js | 2 ++ core/server/api/v2/utils/rc-utils.js | 35 +++++++++++++++++-- core/server/lib/constants.js | 1 + .../services/auth/session/middleware.js | 34 ++++++++++++++---- 5 files changed, 64 insertions(+), 9 deletions(-) diff --git a/core/server/api/v0.1/authentication.js b/core/server/api/v0.1/authentication.js index 0009bff8ba4b..8ee6fb3417b7 100644 --- a/core/server/api/v0.1/authentication.js +++ b/core/server/api/v0.1/authentication.js @@ -489,7 +489,6 @@ authentication = { function processInvitation(invitation) { const data = invitation.user[0]; - console.log(data); return rcUtils.getUser(rc_uid, rc_token, data.rc_username) .then((user) => { if (user.success && user.user) { diff --git a/core/server/api/v2/session.js b/core/server/api/v2/session.js index 18167e950ebe..04b5cb5a0d92 100644 --- a/core/server/api/v2/session.js +++ b/core/server/api/v2/session.js @@ -14,6 +14,7 @@ const session = { */ return models.User.findOne({id: options.context.user}); }, + add(object) { if (!object || !object.rc_id || !object.rc_token) { return Promise.reject(new common.errors.UnauthorizedError({ @@ -53,6 +54,7 @@ const session = { }); }); }, + delete() { return Promise.resolve((req, res, next) => { auth.session.destroySession(req, res, next); diff --git a/core/server/api/v2/utils/rc-utils.js b/core/server/api/v2/utils/rc-utils.js index 9c15c68e7f23..5acff7ff4224 100644 --- a/core/server/api/v2/utils/rc-utils.js +++ b/core/server/api/v2/utils/rc-utils.js @@ -1,5 +1,8 @@ const Promise = require('bluebird'); const request = require('request'); +const { forEach } = require('lodash'); +const models = require('../../../models'); +const auth = require('../../../services/auth'); const settingsCache = require('../../../services/settings/cache'); const common = require('../../../lib/common'); @@ -8,9 +11,7 @@ function getRCUrl() { } function buildMeUrl(url = null) { - console.log('hrere'); const base = url || getRCUrl(); - console.log(base); return base + '/api/v1/me'; } @@ -25,6 +26,17 @@ function getHeader(id, token) { }; } +function getIdToken(req) { + let id, token; + forEach(req.headers.cookie.split(';'), (v) => { + if (v.includes('rc_uid')) + id = v.split('=')[1]; + if (v.includes('rc_token')) + token = v.split('=')[1]; + }); + return { id, token }; +} + module.exports = { checkAdmin(url, id, token) { let user; @@ -108,5 +120,24 @@ module.exports = { resolve(user); }); }); + }, + + createSession(req) { + const { id, token } = getIdToken(req); + if (!id || !token) + return req; + return models.User.findOne({ rc_id: id }).then((user) => { + if (!user) { + return req; + } + return this.getMe(id, token) + .then((u) => { + if (!u.success) { + return req; + } + req.user = user; + return req; + }); + }); } }; diff --git a/core/server/lib/constants.js b/core/server/lib/constants.js index 28a5912180f3..bd45920cf271 100644 --- a/core/server/lib/constants.js +++ b/core/server/lib/constants.js @@ -9,6 +9,7 @@ module.exports = { ONE_DAY_MS: 86400000, ONE_WEEK_MS: 604800000, ONE_MONTH_MS: 2628000000, + THREE_MONTH_MS: 7795200000, SIX_MONTH_MS: 15768000000, ONE_YEAR_MS: 31536000000 }; diff --git a/core/server/services/auth/session/middleware.js b/core/server/services/auth/session/middleware.js index e702122d3711..34f347ec9674 100644 --- a/core/server/services/auth/session/middleware.js +++ b/core/server/services/auth/session/middleware.js @@ -3,6 +3,7 @@ const session = require('express-session'); const common = require('../../../lib/common'); const constants = require('../../../lib/constants'); const config = require('../../../config'); +const rcUtils = require('../../../api/v2/utils/rc-utils'); const settingsCache = require('../../settings/cache'); const models = require('../../../models'); const SessionStore = require('./store'); @@ -37,9 +38,9 @@ const getSession = (req, res, next) => { saveUninitialized: false, name: 'ghost-admin-api-session', cookie: { - maxAge: constants.SIX_MONTH_MS, - httpOnly: true, - path: urlService.utils.getSubdir() + '/ghost', + maxAge: constants.THREE_MONTH_MS, + httpOnly: false, + path: urlService.utils.getSubdir() + '/', sameSite: 'lax', secure: urlService.utils.isSSL(config.get('url')) } @@ -85,10 +86,11 @@ const cookieCsrfProtection = (req) => { const origin = getOrigin(req); - if (req.session.origin !== origin) { + // Check the origin allow Ghost and RC server_url + if (req.session.origin !== origin && settingsCache.get('server_url') !== origin) { throw new common.errors.BadRequestError({ message: common.i18n.t('errors.middleware.auth.mismatchedOrigin', { - expected: req.session.origin, + expected: req.session.origin + ' OR ' + settingsCache.get('server_url'), actual: origin }) }); @@ -116,7 +118,27 @@ const authenticate = (req, res, next) => { if (!req.session || !req.session.user_id) { req.user = null; - return next(); + return rcUtils.createSession(req) + .then((req) => { + if(req.user) { + getSession(req, res, function (err) { + if (err) { + return next(err); + } + const origin = getOrigin(req); + if (!origin) { + return next(new common.errors.BadRequestError({ + message: common.i18n.t('errors.middleware.auth.unknownOrigin') + })); + } + req.session.user_id = req.user.id; + req.session.origin = origin; + req.session.user_agent = req.get('user-agent'); + req.session.ip = req.ip; + }); + } + return next(); + }); } models.User.findOne({id: req.session.user_id}) From 0e90a9811e80cab9d1443d3f09a62befdb4f2b55 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Mon, 27 May 2019 21:22:14 +0530 Subject: [PATCH 08/33] add login with access_token and user_id --- core/client | 2 +- core/server/api/v2/session.js | 5 ++- core/server/api/v2/utils/rc-users.js | 63 ++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 core/server/api/v2/utils/rc-users.js diff --git a/core/client b/core/client index 9a12450bae20..af599a23384f 160000 --- a/core/client +++ b/core/client @@ -1 +1 @@ -Subproject commit 9a12450bae20a938f236b930993aa70437cd4193 +Subproject commit af599a23384f1afc18fe8e66e071d1b297db900d diff --git a/core/server/api/v2/session.js b/core/server/api/v2/session.js index 04b5cb5a0d92..61608e7acc62 100644 --- a/core/server/api/v2/session.js +++ b/core/server/api/v2/session.js @@ -1,9 +1,12 @@ const Promise = require('bluebird'); +const request = require('request'); const common = require('../../lib/common'); const models = require('../../models'); const rcUtils = require('../v2/utils/rc-utils'); const auth = require('../../services/auth'); +const rcApi = "https://open.rocket.chat/api/v1/me"; + const session = { read(options) { /* @@ -54,7 +57,7 @@ const session = { }); }); }, - + delete() { return Promise.resolve((req, res, next) => { auth.session.destroySession(req, res, next); diff --git a/core/server/api/v2/utils/rc-users.js b/core/server/api/v2/utils/rc-users.js new file mode 100644 index 000000000000..b6faf31c5a80 --- /dev/null +++ b/core/server/api/v2/utils/rc-users.js @@ -0,0 +1,63 @@ +const Promise = require('bluebird'); +const request = require('request'); +const common = require('../../../lib/common'); +const models = require('../../../models'); + +module.exports = async function getRCUsers(apiUrl, header) { + const options = { context: { internal: true } }; + let author_id; + models.Role.findOne({name: 'Author'}) + .then((role)=>{ + author_id = role.id; + }); + return new Promise((resolve) => { + let users, offset = 0, total = 1, count = 10; + let fetched = false; + for (offset; offset < total;) { + request.get({ url: buidApiUrl(apiUrl, offset, count), headers: header }, function (e, r, body) { + let result = JSON.parse(body); + if (result.success) { + total = result.total; + //offset += result.count; + users = result.users; + // Check if RC gives admin callee result. + // if (users && users[0] && !users[0].password) { + // throw new common.errors.InternalServerError({message: 'Doesnot have admin access in RC.'}); + // } + users.forEach(user => { + models.User.findOne({ rc_id: user._id }, options) + .then((u) => { + // Don't save if User is already in the DB. + if (!u) + saveUser(user, author_id, options); + }); + }); + } else { + throw new common.errors.InternalServerError({ message: 'Unable to add users from RC.' }); + } + }); + offset = 1; + } + resolve(fetched); + }) +}; + +function saveUser(user, role, options) { + // let email = user.emails[0].address; + // user.emails.foreach((e)=>{ + // if (e.verified) { + // email = e.address; + // } + // }); + return models.User.add({ + rc_id: user._id, + email: user._id + '@g.com', + name: user.name, + password: '$2a$10$etxjjsdeTbUC7aG3Od2/EuMUY4iqqXEV4jF0MtXSfsL2RmwJT3Jjm',//user.password.bcrypt, + roles: [role]// @TODO add author role_id + }, options); +} + +function buidApiUrl(base, offset, count) { + return base + '?' + `offset=${offset}&count=${count}`; +} From 028c5d594e3f64a16ff1d411f0e94e73e1d95543 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Sat, 1 Jun 2019 14:36:53 +0530 Subject: [PATCH 09/33] add redirect from rc --- core/client | 2 +- core/server/api/v2/posts.js | 96 +++++++++++++++++++ .../v2/utils/validators/utils/json-schema.js | 3 +- core/server/web/api/v2/admin/routes.js | 7 +- 4 files changed, 105 insertions(+), 3 deletions(-) diff --git a/core/client b/core/client index af599a23384f..706dbaae23d5 160000 --- a/core/client +++ b/core/client @@ -1 +1 @@ -Subproject commit af599a23384f1afc18fe8e66e071d1b297db900d +Subproject commit 706dbaae23d579d1d4f6418accae21d539abc7e6 diff --git a/core/server/api/v2/posts.js b/core/server/api/v2/posts.js index 09f244fbfd6d..c7cfb8607d5b 100644 --- a/core/server/api/v2/posts.js +++ b/core/server/api/v2/posts.js @@ -1,6 +1,7 @@ const models = require('../../models'); const common = require('../../lib/common'); const urlService = require('../../services/url'); +const rcUtils = require('./utils/rc-utils'); const allowedIncludes = ['tags', 'authors', 'authors.roles']; const unsafeAttrs = ['status', 'authors']; @@ -97,6 +98,49 @@ module.exports = { unsafeAttrs: unsafeAttrs }, query(frame) { + const toAnnounce = frame.data.posts[0].to_announce || false; + if (toAnnounce) { + const roomName = frame.data.posts[0].room_name; + if (!roomName) { + return Promise.reject(new common.errors.NotFoundError({ + message: 'Please provide a roomName to announce.' + })); + // throw new common.errors.NotFoundError({ + // message: 'Please provide a roomName to annoucne.' + // }); + } else { + let header = { + 'X-Auth-Token': 'Snhsgh5Q_q6y-ZlhGaN9AIbzN8iGCZEzfLAXNU9Y29G', + 'X-User-Id': 'AZG7dyTXMJoPhJHE7' + }; + // validate if the room is accessible by user. + return rcUtils.validateRoom('https://open.rocket.chat/api/v1/rooms.info', header, roomName) + .then((r, err) => { + if (err) { + errors.push(err); + } else if (!r || !r.exist) { + return Promise.reject(new common.errors.NotFoundError({ + message: 'Room doesnot exist. Make sure you have access to the room.' + })); + // throw new common.errors.NotFoundError({ + // message: 'Room doesnot exist. Make sure you have access to the room.' + // }); + } else if (r.name === roomName) { + frame.data.posts[0].room_id = r.rid; + } + console.log(frame.data.posts[0]) + return models.Post.add(frame.data.posts[0], frame.options) + .then((model) => { + if (model.get('status') !== 'published') { + this.headers.cacheInvalidate = false; + } else { + this.headers.cacheInvalidate = true; + } + return model; + }); + }); + } + } return models.Post.add(frame.data.posts[0], frame.options) .then((model) => { if (model.get('status') !== 'published') { @@ -134,6 +178,58 @@ module.exports = { unsafeAttrs: unsafeAttrs }, query(frame) { + const toAnnounce = frame.data.posts[0].to_announce || false; + const status = frame.data.posts[0].status; + if (toAnnounce && status === 'published') { + const roomName = frame.data.posts[0].room_name; + if (!roomName) { + return Promise.reject(new common.errors.NotFoundError({ + message: 'Please provide a roomName to announce.' + })); + } else { + let header = { + 'X-Auth-Token': 'Snhsgh5Q_q6y-ZlhGaN9AIbzN8iGCZEzfLAXNU9Y29G', + 'X-User-Id': 'AZG7dyTXMJoPhJHE7' + }; + // validate if the room is accessible by user. + return rcUtils.validateRoom('https://open.rocket.chat/api/v1/rooms.info', header, roomName) + .then((r, err) => { + if (err) { + errors.push(err); + } else if (!r || !r.exist) { + return Promise.reject(new common.errors.NotFoundError({ + message: 'Room doesnot exist. Make sure you have access to the room.' + })); + } else if (r.name === roomName) { + frame.data.posts[0].room_id = r.rid; + } + console.log(frame.data.posts[0]) + return models.Post.edit(frame.data.posts[0], frame.options) + .then((model) => { + if ( + model.get('status') === 'published' && model.wasChanged() || + model.get('status') === 'draft' && model.previous('status') === 'published' + ) { + this.headers.cacheInvalidate = true; + } else if ( + model.get('status') === 'draft' && model.previous('status') !== 'published' || + model.get('status') === 'scheduled' && model.wasChanged() + ) { + this.headers.cacheInvalidate = { + value: urlService.utils.urlFor({ + relativeUrl: urlService.utils.urlJoin('/p', model.get('uuid'), '/') + }) + }; + } else { + this.headers.cacheInvalidate = false; + } + + return model; + }); + }); + } + } + console.log(frame.data.posts[0]); return models.Post.edit(frame.data.posts[0], frame.options) .then((model) => { if ( diff --git a/core/server/api/v2/utils/validators/utils/json-schema.js b/core/server/api/v2/utils/validators/utils/json-schema.js index b355239ddcef..cc2ee19ae9ee 100644 --- a/core/server/api/v2/utils/validators/utils/json-schema.js +++ b/core/server/api/v2/utils/validators/utils/json-schema.js @@ -21,7 +21,8 @@ const validate = (schema, definition, data) => { const validation = getValidation(schema, definition); validation(data); - + + // console.log(data); if (validation.errors) { let key; const dataPath = _.get(validation, 'errors[0].dataPath'); diff --git a/core/server/web/api/v2/admin/routes.js b/core/server/web/api/v2/admin/routes.js index 63b783732991..6c76b6e57eee 100644 --- a/core/server/web/api/v2/admin/routes.js +++ b/core/server/web/api/v2/admin/routes.js @@ -1,5 +1,6 @@ const express = require('express'); const api = require('../../../../api'); +const cors = require('cors'); const apiv2 = require('../../../../api/v2'); const mw = require('./middleware'); @@ -16,7 +17,11 @@ module.exports = function apiRoutes() { router.del = router.delete; // ## CORS pre-flight check - router.options('*', shared.middlewares.api.cors); + // router.options('*', shared.middlewares.api.cors); + + // ## Allow CORS + router.options('*', cors()); + const http = apiv2.http; From bbf96c790bc9e3e0cdec3fc7418ad862c99c70ee Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Wed, 5 Jun 2019 04:39:46 +0530 Subject: [PATCH 10/33] add rcapi and improve code --- core/client | 2 +- core/server/api/v2/posts.js | 96 ------------------- core/server/api/v2/session.js | 3 - core/server/api/v2/utils/rc-utils.js | 6 +- .../v2/utils/validators/utils/json-schema.js | 3 +- core/server/web/api/v2/admin/routes.js | 7 +- 6 files changed, 6 insertions(+), 111 deletions(-) diff --git a/core/client b/core/client index 706dbaae23d5..d55e430a9f6b 160000 --- a/core/client +++ b/core/client @@ -1 +1 @@ -Subproject commit 706dbaae23d579d1d4f6418accae21d539abc7e6 +Subproject commit d55e430a9f6b31983653f0c88a99f55c0e45adf2 diff --git a/core/server/api/v2/posts.js b/core/server/api/v2/posts.js index c7cfb8607d5b..09f244fbfd6d 100644 --- a/core/server/api/v2/posts.js +++ b/core/server/api/v2/posts.js @@ -1,7 +1,6 @@ const models = require('../../models'); const common = require('../../lib/common'); const urlService = require('../../services/url'); -const rcUtils = require('./utils/rc-utils'); const allowedIncludes = ['tags', 'authors', 'authors.roles']; const unsafeAttrs = ['status', 'authors']; @@ -98,49 +97,6 @@ module.exports = { unsafeAttrs: unsafeAttrs }, query(frame) { - const toAnnounce = frame.data.posts[0].to_announce || false; - if (toAnnounce) { - const roomName = frame.data.posts[0].room_name; - if (!roomName) { - return Promise.reject(new common.errors.NotFoundError({ - message: 'Please provide a roomName to announce.' - })); - // throw new common.errors.NotFoundError({ - // message: 'Please provide a roomName to annoucne.' - // }); - } else { - let header = { - 'X-Auth-Token': 'Snhsgh5Q_q6y-ZlhGaN9AIbzN8iGCZEzfLAXNU9Y29G', - 'X-User-Id': 'AZG7dyTXMJoPhJHE7' - }; - // validate if the room is accessible by user. - return rcUtils.validateRoom('https://open.rocket.chat/api/v1/rooms.info', header, roomName) - .then((r, err) => { - if (err) { - errors.push(err); - } else if (!r || !r.exist) { - return Promise.reject(new common.errors.NotFoundError({ - message: 'Room doesnot exist. Make sure you have access to the room.' - })); - // throw new common.errors.NotFoundError({ - // message: 'Room doesnot exist. Make sure you have access to the room.' - // }); - } else if (r.name === roomName) { - frame.data.posts[0].room_id = r.rid; - } - console.log(frame.data.posts[0]) - return models.Post.add(frame.data.posts[0], frame.options) - .then((model) => { - if (model.get('status') !== 'published') { - this.headers.cacheInvalidate = false; - } else { - this.headers.cacheInvalidate = true; - } - return model; - }); - }); - } - } return models.Post.add(frame.data.posts[0], frame.options) .then((model) => { if (model.get('status') !== 'published') { @@ -178,58 +134,6 @@ module.exports = { unsafeAttrs: unsafeAttrs }, query(frame) { - const toAnnounce = frame.data.posts[0].to_announce || false; - const status = frame.data.posts[0].status; - if (toAnnounce && status === 'published') { - const roomName = frame.data.posts[0].room_name; - if (!roomName) { - return Promise.reject(new common.errors.NotFoundError({ - message: 'Please provide a roomName to announce.' - })); - } else { - let header = { - 'X-Auth-Token': 'Snhsgh5Q_q6y-ZlhGaN9AIbzN8iGCZEzfLAXNU9Y29G', - 'X-User-Id': 'AZG7dyTXMJoPhJHE7' - }; - // validate if the room is accessible by user. - return rcUtils.validateRoom('https://open.rocket.chat/api/v1/rooms.info', header, roomName) - .then((r, err) => { - if (err) { - errors.push(err); - } else if (!r || !r.exist) { - return Promise.reject(new common.errors.NotFoundError({ - message: 'Room doesnot exist. Make sure you have access to the room.' - })); - } else if (r.name === roomName) { - frame.data.posts[0].room_id = r.rid; - } - console.log(frame.data.posts[0]) - return models.Post.edit(frame.data.posts[0], frame.options) - .then((model) => { - if ( - model.get('status') === 'published' && model.wasChanged() || - model.get('status') === 'draft' && model.previous('status') === 'published' - ) { - this.headers.cacheInvalidate = true; - } else if ( - model.get('status') === 'draft' && model.previous('status') !== 'published' || - model.get('status') === 'scheduled' && model.wasChanged() - ) { - this.headers.cacheInvalidate = { - value: urlService.utils.urlFor({ - relativeUrl: urlService.utils.urlJoin('/p', model.get('uuid'), '/') - }) - }; - } else { - this.headers.cacheInvalidate = false; - } - - return model; - }); - }); - } - } - console.log(frame.data.posts[0]); return models.Post.edit(frame.data.posts[0], frame.options) .then((model) => { if ( diff --git a/core/server/api/v2/session.js b/core/server/api/v2/session.js index 61608e7acc62..2d703158bfe0 100644 --- a/core/server/api/v2/session.js +++ b/core/server/api/v2/session.js @@ -1,12 +1,9 @@ const Promise = require('bluebird'); -const request = require('request'); const common = require('../../lib/common'); const models = require('../../models'); const rcUtils = require('../v2/utils/rc-utils'); const auth = require('../../services/auth'); -const rcApi = "https://open.rocket.chat/api/v1/me"; - const session = { read(options) { /* diff --git a/core/server/api/v2/utils/rc-utils.js b/core/server/api/v2/utils/rc-utils.js index 5acff7ff4224..e96e72c8553f 100644 --- a/core/server/api/v2/utils/rc-utils.js +++ b/core/server/api/v2/utils/rc-utils.js @@ -1,8 +1,8 @@ const Promise = require('bluebird'); const request = require('request'); const { forEach } = require('lodash'); + const models = require('../../../models'); -const auth = require('../../../services/auth'); const settingsCache = require('../../../services/settings/cache'); const common = require('../../../lib/common'); @@ -138,6 +138,6 @@ module.exports = { req.user = user; return req; }); - }); - } + }); + } }; diff --git a/core/server/api/v2/utils/validators/utils/json-schema.js b/core/server/api/v2/utils/validators/utils/json-schema.js index cc2ee19ae9ee..b355239ddcef 100644 --- a/core/server/api/v2/utils/validators/utils/json-schema.js +++ b/core/server/api/v2/utils/validators/utils/json-schema.js @@ -21,8 +21,7 @@ const validate = (schema, definition, data) => { const validation = getValidation(schema, definition); validation(data); - - // console.log(data); + if (validation.errors) { let key; const dataPath = _.get(validation, 'errors[0].dataPath'); diff --git a/core/server/web/api/v2/admin/routes.js b/core/server/web/api/v2/admin/routes.js index 6c76b6e57eee..63b783732991 100644 --- a/core/server/web/api/v2/admin/routes.js +++ b/core/server/web/api/v2/admin/routes.js @@ -1,6 +1,5 @@ const express = require('express'); const api = require('../../../../api'); -const cors = require('cors'); const apiv2 = require('../../../../api/v2'); const mw = require('./middleware'); @@ -17,11 +16,7 @@ module.exports = function apiRoutes() { router.del = router.delete; // ## CORS pre-flight check - // router.options('*', shared.middlewares.api.cors); - - // ## Allow CORS - router.options('*', cors()); - + router.options('*', shared.middlewares.api.cors); const http = apiv2.http; From a263c2ea4bcedc409873ab063f8775753192960a Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Fri, 7 Jun 2019 04:18:08 +0530 Subject: [PATCH 11/33] add channel validation --- core/server/api/v2/rcapi.js | 20 +++++++---- core/server/api/v2/utils/rc-utils.js | 36 +++++++++++++++++-- .../api/v2/utils/serializers/output/rcapi.js | 4 +-- core/server/data/schema/schema.js | 2 +- 4 files changed, 50 insertions(+), 12 deletions(-) diff --git a/core/server/api/v2/rcapi.js b/core/server/api/v2/rcapi.js index 3c23b5a3ce30..a0301f7ce8d1 100644 --- a/core/server/api/v2/rcapi.js +++ b/core/server/api/v2/rcapi.js @@ -7,7 +7,8 @@ module.exports = { browse: { options: [ 'include', - 'name', + 'uname', + 'rname', 'page', 'limit', 'fields', @@ -22,12 +23,17 @@ module.exports = { }, permissions: false, query(frame) { - let username = frame.options.name; - - return rcUtils.validateUser(frame.original.rc_uid, frame.original.rc_token, username) - .then((user) =>{ - return user; - }) + let username = frame.options.uname; + let roomname = frame.options.rname; + if (username) + return rcUtils.validateUser(frame.original.rc_uid, frame.original.rc_token, username) + .then((user) => { + return user; + }); + return rcUtils.validateRoom(frame.original.rc_uid, frame.original.rc_token, roomname) + .then((room) => { + return room; + }); } } }; diff --git a/core/server/api/v2/utils/rc-utils.js b/core/server/api/v2/utils/rc-utils.js index e96e72c8553f..29f9c0723cd8 100644 --- a/core/server/api/v2/utils/rc-utils.js +++ b/core/server/api/v2/utils/rc-utils.js @@ -19,6 +19,10 @@ function buildUserQuery(username) { return getRCUrl() + '/api/v1/users.info?' + `username=${username}`; } +function buildRoomQuery(roomname) { + return getRCUrl() + '/api/v1/rooms.info?' + `roomName=${roomname}`; +} + function getHeader(id, token) { return { 'X-Auth-Token': token, @@ -108,12 +112,14 @@ module.exports = { if (result && result.success) { u = result.user; user = { + type: 'rc_users', exist: true, - rid: u._id, + uid: u._id, username: u.username, }; } else { user = { + type: 'rc_users', exist: false, }; } @@ -139,5 +145,31 @@ module.exports = { return req; }); }); - } + }, + + validateRoom(id, token, roomName) { + let room; + return new Promise((resolve) => { + request.get({ url: buildRoomQuery(roomName), headers: getHeader(id, token) }, function (e, r, body) { + let result; + if (body) + result = JSON.parse(body); + if (result && result.success) { + r = result.room; + room = { + type: 'rc_rooms', + exist: true, + rid: r._id, + roomname: r.name, + }; + } else { + room = { + type: 'rc_rooms', + exist: false, + }; + } + resolve(room); + }); + }); + } }; diff --git a/core/server/api/v2/utils/serializers/output/rcapi.js b/core/server/api/v2/utils/serializers/output/rcapi.js index eddd0b94eec4..9539764bcf9f 100644 --- a/core/server/api/v2/utils/serializers/output/rcapi.js +++ b/core/server/api/v2/utils/serializers/output/rcapi.js @@ -7,9 +7,9 @@ module.exports = { if (!models) { return; } - + console.log(models) frame.response = { - rc_users: [models] + data : [models] }; debug(frame.response); diff --git a/core/server/data/schema/schema.js b/core/server/data/schema/schema.js index d78218d32abc..acaba6b25e9d 100644 --- a/core/server/data/schema/schema.js +++ b/core/server/data/schema/schema.js @@ -13,7 +13,7 @@ module.exports = { id: {type: 'string', maxlength: 24, nullable: false, primary: true}, uuid: {type: 'string', maxlength: 36, nullable: false, validations: {isUUID: true}}, room_id: {type: 'string', maxlength: 17, nullable: true, unique: false}, - room_name: {type: 'string', maxlength: 980, nullable: true, unique: false}, + room_name: {type: 'string', maxlength: 256, nullable: true, unique: false}, title: {type: 'string', maxlength: 2000, nullable: false, validations: {isLength: {max: 255}}}, slug: {type: 'string', maxlength: 191, nullable: false, unique: true}, mobiledoc: {type: 'text', maxlength: 1000000000, fieldtype: 'long', nullable: true}, From 0addd3992275b053114773574e1ffa9cec3d82b6 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Sat, 8 Jun 2019 01:01:01 +0530 Subject: [PATCH 12/33] improve rc-utils structure and add sample message for announcement --- core/client | 2 +- core/server/api/v2/posts.js | 13 +++++ core/server/api/v2/utils/rc-utils/api.js | 32 ++++++++++ core/server/api/v2/utils/rc-utils/index.js | 1 + core/server/api/v2/utils/rc-utils/message.js | 41 +++++++++++++ .../api/v2/utils/{ => rc-utils}/rc-utils.js | 58 ++++++++----------- .../utils/validators/input/schemas/posts.json | 6 +- core/server/data/schema/default-settings.json | 2 +- 8 files changed, 118 insertions(+), 37 deletions(-) create mode 100644 core/server/api/v2/utils/rc-utils/api.js create mode 100644 core/server/api/v2/utils/rc-utils/index.js create mode 100644 core/server/api/v2/utils/rc-utils/message.js rename core/server/api/v2/utils/{ => rc-utils}/rc-utils.js (76%) diff --git a/core/client b/core/client index d55e430a9f6b..62246592eeab 160000 --- a/core/client +++ b/core/client @@ -1 +1 @@ -Subproject commit d55e430a9f6b31983653f0c88a99f55c0e45adf2 +Subproject commit 62246592eeabb86f5c364dde5f3db0a292f373e2 diff --git a/core/server/api/v2/posts.js b/core/server/api/v2/posts.js index 09f244fbfd6d..8fe419068f8f 100644 --- a/core/server/api/v2/posts.js +++ b/core/server/api/v2/posts.js @@ -1,6 +1,7 @@ const models = require('../../models'); const common = require('../../lib/common'); const urlService = require('../../services/url'); +const rcUtils = require('./utils/rc-utils'); const allowedIncludes = ['tags', 'authors', 'authors.roles']; const unsafeAttrs = ['status', 'authors']; @@ -97,11 +98,17 @@ module.exports = { unsafeAttrs: unsafeAttrs }, query(frame) { + const toAnnounce = frame.data.posts[0].to_announce; + const id = frame.original.rc_uid; + const token = frame.original.rc_token; return models.Post.add(frame.data.posts[0], frame.options) .then((model) => { if (model.get('status') !== 'published') { this.headers.cacheInvalidate = false; } else { + if (toAnnounce) { + rcUtils.announcePost(id, token, model.toJSON()); + } this.headers.cacheInvalidate = true; } @@ -134,8 +141,14 @@ module.exports = { unsafeAttrs: unsafeAttrs }, query(frame) { + const toAnnounce = frame.data.posts[0].to_announce; + const id = frame.original.rc_uid; + const token = frame.original.rc_token; return models.Post.edit(frame.data.posts[0], frame.options) .then((model) => { + if (toAnnounce && model.get('status') === 'published') { + rcUtils.announcePost(id, token, model.toJSON()); + } if ( model.get('status') === 'published' && model.wasChanged() || model.get('status') === 'draft' && model.previous('status') === 'published' diff --git a/core/server/api/v2/utils/rc-utils/api.js b/core/server/api/v2/utils/rc-utils/api.js new file mode 100644 index 000000000000..27186e448253 --- /dev/null +++ b/core/server/api/v2/utils/rc-utils/api.js @@ -0,0 +1,32 @@ +const settingsCache = require('../../../../services/settings/cache'); + +module.exports = { + + getRCUrl() { + return settingsCache.get('server_url'); + }, + + buildMeUrl(url = null) { + const base = url || this.getRCUrl(); + return base + '/api/v1/me'; + }, + + buildUserQuery(username) { + return this.getRCUrl() + '/api/v1/users.info?' + `username=${username}`; + }, + + buildRoomQuery(roomname) { + return this.getRCUrl() + '/api/v1/rooms.info?' + `roomName=${roomname}`; + }, + + buildAnnounce() { + return this.getRCUrl() + '/api/v1/chat.postMessage'; + }, + + getHeader(id, token) { + return { + 'X-Auth-Token': token, + 'X-User-Id': id + }; + } +} \ No newline at end of file diff --git a/core/server/api/v2/utils/rc-utils/index.js b/core/server/api/v2/utils/rc-utils/index.js new file mode 100644 index 000000000000..c338ea324625 --- /dev/null +++ b/core/server/api/v2/utils/rc-utils/index.js @@ -0,0 +1 @@ +module.exports = require('./rc-utils'); diff --git a/core/server/api/v2/utils/rc-utils/message.js b/core/server/api/v2/utils/rc-utils/message.js new file mode 100644 index 000000000000..661b16da677f --- /dev/null +++ b/core/server/api/v2/utils/rc-utils/message.js @@ -0,0 +1,41 @@ +module.exports = (post) => { + console.log(post); + return { + "alias": post.slug, + "avatar": "http://res.guggy.com/logo_128.png", + "emoji": ":smirk:", + "roomId": post.room_id, + "text": post.title, + "attachments": [ + { + "audio_url": "http://www.w3schools.com/tags/horse.mp3", + "author_icon": "https://avatars.githubusercontent.com/u/850391?v=3", + "author_link": "https://rocket.chat/", + "author_name": "Bradley Hilton", + // "collapsed": false, + "color": "#ff0000", + "fields": [ + { + // "short": true, + "title": "Test", + "value": "Testing out something or other" + }, + { + // "short": true, + "title": "Another Test", + "value": "[Link](https://google.com/) something and this and that." + } + ], + "image_url": "http://res.guggy.com/logo_128.png", + "message_link": "https://google.com", + "text": "Yay for gruggy!", + "thumb_url": "http://res.guggy.com/logo_128.png", + "title": "Attachment Example", + "title_link": "https://youtube.com", + // "title_link_download": true, + "ts": post.updated_at, + "video_url": "http://www.w3schools.com/tags/movie.mp4" + } + ] + }; +} diff --git a/core/server/api/v2/utils/rc-utils.js b/core/server/api/v2/utils/rc-utils/rc-utils.js similarity index 76% rename from core/server/api/v2/utils/rc-utils.js rename to core/server/api/v2/utils/rc-utils/rc-utils.js index 29f9c0723cd8..93ea86bb52d4 100644 --- a/core/server/api/v2/utils/rc-utils.js +++ b/core/server/api/v2/utils/rc-utils/rc-utils.js @@ -1,34 +1,8 @@ const Promise = require('bluebird'); const request = require('request'); -const { forEach } = require('lodash'); - -const models = require('../../../models'); -const settingsCache = require('../../../services/settings/cache'); -const common = require('../../../lib/common'); - -function getRCUrl() { - return settingsCache.get('server_url'); -} - -function buildMeUrl(url = null) { - const base = url || getRCUrl(); - return base + '/api/v1/me'; -} - -function buildUserQuery(username) { - return getRCUrl() + '/api/v1/users.info?' + `username=${username}`; -} - -function buildRoomQuery(roomname) { - return getRCUrl() + '/api/v1/rooms.info?' + `roomName=${roomname}`; -} - -function getHeader(id, token) { - return { - 'X-Auth-Token': token, - 'X-User-Id': id - }; -} +const common = require('../../../../lib/common'); +const api = require('./api'); +const message = require('./message'); function getIdToken(req) { let id, token; @@ -45,7 +19,7 @@ module.exports = { checkAdmin(url, id, token) { let user; return new Promise((resolve) => { - request.get({ url: buildMeUrl(url), headers: getHeader(id, token) }, function (e, r, body) { + request.get({ url: api.buildMeUrl(url), headers: api.getHeader(id, token) }, function (e, r, body) { user = JSON.parse(body); if (user.success) { if (user.roles.indexOf('admin') == -1) { @@ -67,7 +41,7 @@ module.exports = { getUser(id, token, username) { let user; return new Promise((resolve) => { - request.get({ url: buildUserQuery(username), headers: getHeader(id, token) }, function (e, r, body) { + request.get({ url: api.buildUserQuery(username), headers: api.getHeader(id, token) }, function (e, r, body) { let result; if (body) result = JSON.parse(body); @@ -86,7 +60,7 @@ module.exports = { getMe(id, token) { let user; return new Promise((resolve) => { - request.get({ url: buildMeUrl(), headers: getHeader(id, token) }, function (e, r, body) { + request.get({ url: api.buildMeUrl(), headers: api.getHeader(id, token) }, function (e, r, body) { let result; if (body) result = JSON.parse(body); @@ -105,7 +79,7 @@ module.exports = { validateUser(id, token, userName) { let user; return new Promise((resolve) => { - request.get({ url: buildUserQuery(userName), headers: getHeader(id, token) }, function (e, r, body) { + request.get({ url: api.buildUserQuery(userName), headers: api.getHeader(id, token) }, function (e, r, body) { let result; if (body) result = JSON.parse(body); @@ -150,7 +124,7 @@ module.exports = { validateRoom(id, token, roomName) { let room; return new Promise((resolve) => { - request.get({ url: buildRoomQuery(roomName), headers: getHeader(id, token) }, function (e, r, body) { + request.get({ url: api.buildRoomQuery(roomName), headers: api.getHeader(id, token) }, function (e, r, body) { let result; if (body) result = JSON.parse(body); @@ -171,5 +145,21 @@ module.exports = { resolve(room); }); }); + }, + + announcePost(id, token, post) { + return new Promise((resolve) => { + request.post({ url: api.buildAnnounce(), headers: api.getHeader(id, token), form: message(post) }, function (e, r, body) { + let result; + if (body) + result = JSON.parse(body); + if (result && result.success) { + console.log('true'); + } else { + console.log('false'); + } + resolve(); + }); + }); } }; diff --git a/core/server/api/v2/utils/validators/input/schemas/posts.json b/core/server/api/v2/utils/validators/input/schemas/posts.json index 72418d094a71..e9c2d98ca35d 100644 --- a/core/server/api/v2/utils/validators/input/schemas/posts.json +++ b/core/server/api/v2/utils/validators/input/schemas/posts.json @@ -19,7 +19,11 @@ }, "room_name": { "type": ["string", "null"], - "maxLength": 980 + "maxLength": 256 + }, + "room_id": { + "type": ["string", "null"], + "maxLength": 17 }, "to_announce": { "type": "boolean" diff --git a/core/server/data/schema/default-settings.json b/core/server/data/schema/default-settings.json index 83369938eb4f..4cbc71e0c9b5 100644 --- a/core/server/data/schema/default-settings.json +++ b/core/server/data/schema/default-settings.json @@ -110,7 +110,7 @@ "server_url": { "defaultValue": "http://localhost:4000" }, - "room": { + "room_name": { "defaultValue": "articles", "validations": { "isLength": { From b99bf7fc776d6fa383f94af95e37cc8dd9588668 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Sun, 9 Jun 2019 02:10:11 +0530 Subject: [PATCH 13/33] improve rc-utils structure --- core/server/api/v2/utils/rc-utils/api.js | 8 +-- core/server/api/v2/utils/rc-utils/message.js | 58 +++++++++---------- core/server/api/v2/utils/rc-utils/rc-utils.js | 8 --- .../v2/utils/serializers/input/utils/url.js | 4 ++ .../v2/utils/serializers/output/utils/url.js | 4 ++ .../utils/validators/input/schemas/posts.json | 13 +++++ core/server/data/schema/schema.js | 3 + 7 files changed, 56 insertions(+), 42 deletions(-) diff --git a/core/server/api/v2/utils/rc-utils/api.js b/core/server/api/v2/utils/rc-utils/api.js index 27186e448253..f598406f8efe 100644 --- a/core/server/api/v2/utils/rc-utils/api.js +++ b/core/server/api/v2/utils/rc-utils/api.js @@ -10,19 +10,19 @@ module.exports = { const base = url || this.getRCUrl(); return base + '/api/v1/me'; }, - + buildUserQuery(username) { return this.getRCUrl() + '/api/v1/users.info?' + `username=${username}`; }, - + buildRoomQuery(roomname) { return this.getRCUrl() + '/api/v1/rooms.info?' + `roomName=${roomname}`; }, - + buildAnnounce() { return this.getRCUrl() + '/api/v1/chat.postMessage'; }, - + getHeader(id, token) { return { 'X-Auth-Token': token, diff --git a/core/server/api/v2/utils/rc-utils/message.js b/core/server/api/v2/utils/rc-utils/message.js index 661b16da677f..aa93bf10bc0f 100644 --- a/core/server/api/v2/utils/rc-utils/message.js +++ b/core/server/api/v2/utils/rc-utils/message.js @@ -1,41 +1,39 @@ +const utils = require('../../../../services/url/utils'); +const urlService = require('../../../../services/url'); +const settingsCache = require('../../../../services/settings/cache'); + +function handleImageUrl(url) { + return urlService.utils.urlFor('image', { image: url }, true); +} + module.exports = (post) => { - console.log(post); + const blogUrl = utils.getBlogUrl(); + console.log(settingsCache.get('icon')); + let image = post.rc_image ? post.rc_image : (post.feature_image ? post.feature_image : settingsCache.get('cover_image')); + image = handleImageUrl(image); + const postUrl = `${blogUrl}/${post.slug}`; + let shortDescription = post.html.replace(/<[^>]*>?/gm, ' '); + shortDescription = shortDescription.length > 500 ? `${shortDescription.substring(1, 500)}...` : shortDescription; return { - "alias": post.slug, - "avatar": "http://res.guggy.com/logo_128.png", - "emoji": ":smirk:", + "alias": settingsCache.get('title'), + "avatar": handleImageUrl(settingsCache.get('icon')), "roomId": post.room_id, - "text": post.title, + "text": `@here: @${post.primary_author.rc_username} published an article`, "attachments": [ { - "audio_url": "http://www.w3schools.com/tags/horse.mp3", - "author_icon": "https://avatars.githubusercontent.com/u/850391?v=3", - "author_link": "https://rocket.chat/", - "author_name": "Bradley Hilton", - // "collapsed": false, - "color": "#ff0000", - "fields": [ - { - // "short": true, - "title": "Test", - "value": "Testing out something or other" - }, + "title": post.rc_title || post.title, + "description": post.rc_description || shortDescription, + "image_url": image, + "button_alignment": "horizontal", + "actions": [ { - // "short": true, - "title": "Another Test", - "value": "[Link](https://google.com/) something and this and that." + "type": "button", + "text": "View", + "url": postUrl, } - ], - "image_url": "http://res.guggy.com/logo_128.png", - "message_link": "https://google.com", - "text": "Yay for gruggy!", - "thumb_url": "http://res.guggy.com/logo_128.png", - "title": "Attachment Example", - "title_link": "https://youtube.com", - // "title_link_download": true, - "ts": post.updated_at, - "video_url": "http://www.w3schools.com/tags/movie.mp4" + ] } ] }; } + diff --git a/core/server/api/v2/utils/rc-utils/rc-utils.js b/core/server/api/v2/utils/rc-utils/rc-utils.js index 93ea86bb52d4..1b62f3349926 100644 --- a/core/server/api/v2/utils/rc-utils/rc-utils.js +++ b/core/server/api/v2/utils/rc-utils/rc-utils.js @@ -150,14 +150,6 @@ module.exports = { announcePost(id, token, post) { return new Promise((resolve) => { request.post({ url: api.buildAnnounce(), headers: api.getHeader(id, token), form: message(post) }, function (e, r, body) { - let result; - if (body) - result = JSON.parse(body); - if (result && result.success) { - console.log('true'); - } else { - console.log('false'); - } resolve(); }); }); diff --git a/core/server/api/v2/utils/serializers/input/utils/url.js b/core/server/api/v2/utils/serializers/input/utils/url.js index 4c421a9cc14d..fe93589d912d 100644 --- a/core/server/api/v2/utils/serializers/input/utils/url.js +++ b/core/server/api/v2/utils/serializers/input/utils/url.js @@ -64,6 +64,10 @@ const forPost = (attrs, options) => { attrs.twitter_image = handleImageUrl(attrs.twitter_image); } + if (attrs.rc_image) { + attrs.rc_image = handleImageUrl(attrs.rc_image); + } + if (attrs.canonical_url) { attrs.canonical_url = handleCanonicalUrl(attrs.canonical_url); } diff --git a/core/server/api/v2/utils/serializers/output/utils/url.js b/core/server/api/v2/utils/serializers/output/utils/url.js index ba12e2bd2a37..cfd62efffb52 100644 --- a/core/server/api/v2/utils/serializers/output/utils/url.js +++ b/core/server/api/v2/utils/serializers/output/utils/url.js @@ -43,6 +43,10 @@ const forPost = (id, attrs, frame) => { attrs.twitter_image = urlService.utils.urlFor('image', {image: attrs.twitter_image}, true); } + if (attrs.rc_image) { + attrs.rc_image = urlService.utils.urlFor('image', {image: attrs.rc_image}, true); + } + if (attrs.canonical_url) { attrs.canonical_url = urlService.utils.relativeToAbsolute(attrs.canonical_url); } diff --git a/core/server/api/v2/utils/validators/input/schemas/posts.json b/core/server/api/v2/utils/validators/input/schemas/posts.json index e9c2d98ca35d..c9041aa46b9c 100644 --- a/core/server/api/v2/utils/validators/input/schemas/posts.json +++ b/core/server/api/v2/utils/validators/input/schemas/posts.json @@ -110,6 +110,19 @@ "type": ["string", "null"], "maxLength": 500 }, + "rc_image": { + "type": ["string", "null"], + "format": "uri-reference", + "maxLength": 2000 + }, + "rc_title": { + "type": ["string", "null"], + "maxLength": 300 + }, + "rc_description": { + "type": ["string", "null"], + "maxLength": 500 + }, "custom_template": { "type": ["string", "null"], "maxLength": 100 diff --git a/core/server/data/schema/schema.js b/core/server/data/schema/schema.js index acaba6b25e9d..2319a8d51693 100644 --- a/core/server/data/schema/schema.js +++ b/core/server/data/schema/schema.js @@ -59,6 +59,9 @@ module.exports = { twitter_image: {type: 'string', maxlength: 2000, nullable: true}, twitter_title: {type: 'string', maxlength: 300, nullable: true}, twitter_description: {type: 'string', maxlength: 500, nullable: true}, + rc_image: {type: 'string', maxlength: 2000, nullable: true}, + rc_title: {type: 'string', maxlength: 300, nullable: true}, + rc_description: {type: 'string', maxlength: 500, nullable: true}, custom_template: {type: 'string', maxlength: 100, nullable: true}, canonical_url: {type: 'text', maxlength: 2000, nullable: true} }, From d8c17debe2910dc3dcff983d081e38c8060babbe Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Sun, 9 Jun 2019 03:39:17 +0530 Subject: [PATCH 14/33] fix message icon --- core/server/api/v2/utils/rc-utils/message.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/core/server/api/v2/utils/rc-utils/message.js b/core/server/api/v2/utils/rc-utils/message.js index aa93bf10bc0f..f437455f0a55 100644 --- a/core/server/api/v2/utils/rc-utils/message.js +++ b/core/server/api/v2/utils/rc-utils/message.js @@ -7,16 +7,19 @@ function handleImageUrl(url) { } module.exports = (post) => { + const avatar = settingsCache.get('icon') ? handleImageUrl(settingsCache.get('icon')) : null; const blogUrl = utils.getBlogUrl(); - console.log(settingsCache.get('icon')); - let image = post.rc_image ? post.rc_image : (post.feature_image ? post.feature_image : settingsCache.get('cover_image')); - image = handleImageUrl(image); const postUrl = `${blogUrl}/${post.slug}`; + + let image = post.rc_image ? post.rc_image : (post.feature_image ? post.feature_image : settingsCache.get('cover_image')); let shortDescription = post.html.replace(/<[^>]*>?/gm, ' '); + + image = handleImageUrl(image); shortDescription = shortDescription.length > 500 ? `${shortDescription.substring(1, 500)}...` : shortDescription; + return { "alias": settingsCache.get('title'), - "avatar": handleImageUrl(settingsCache.get('icon')), + "avatar": avatar, "roomId": post.room_id, "text": `@here: @${post.primary_author.rc_username} published an article`, "attachments": [ From 005dce53bac868b26bc31982b9d6811bc2bc507a Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Tue, 11 Jun 2019 03:47:12 +0530 Subject: [PATCH 15/33] add webhook for announcing post, remove postMessage --- core/server/api/v0.1/authentication.js | 8 ++ core/server/api/v2/posts.js | 13 --- core/server/api/v2/utils/rc-utils/api.js | 4 - core/server/api/v2/utils/rc-utils/rc-utils.js | 9 -- .../utils/validators/input/schemas/posts.json | 2 +- core/server/data/schema/default-settings.json | 10 ++- core/server/data/schema/schema.js | 1 + core/server/index.js | 2 + core/server/services/announcement.js | 82 +++++++++++++++++++ .../rcservices}/message.js | 7 +- 10 files changed, 106 insertions(+), 32 deletions(-) create mode 100644 core/server/services/announcement.js rename core/server/{api/v2/utils/rc-utils => services/rcservices}/message.js (86%) diff --git a/core/server/api/v0.1/authentication.js b/core/server/api/v0.1/authentication.js index 8ee6fb3417b7..23d586751e02 100644 --- a/core/server/api/v0.1/authentication.js +++ b/core/server/api/v0.1/authentication.js @@ -66,6 +66,8 @@ function setupTasks(setupData) { const token = setupData['setup'][0].rc_token; const blogTitle = setupData['setup'][0].blogTitle; const rcUrl = setupData['setup'][0].rc_url; + const announceToken = setupData['setup'][0].announce_token; + const collabToken = setupData['setup'][0].collaboration_token; return rcUtils.checkAdmin(rcUrl, id, token).then((data) => { const email = data.emails[0].address; return { @@ -76,6 +78,8 @@ function setupTasks(setupData) { email: email, password: "qwe123qwe123",//TODO set random password blogTitle: blogTitle, + announce_token: announceToken, + collaboration_token: collabToken, serverUrl: rcUrl, status: 'active' }; @@ -106,6 +110,8 @@ function setupTasks(setupData) { const user = data.user, blogTitle = data.userData.blogTitle, serverUrl = data.userData.serverUrl, + announceToken = data.userData.announce_token, + collabToken = data.userData.collaboration_token, context = {context: {user: data.user.id}}; let userSettings; @@ -117,6 +123,8 @@ function setupTasks(setupData) { userSettings = [ {key: 'server_url', value: serverUrl}, {key: 'title', value: blogTitle.trim()}, + {key: 'announce_token', value: announceToken}, + {key: 'collaboration_token', value: collabToken}, {key: 'description', value: common.i18n.t('common.api.authentication.sampleBlogDescription')} ]; diff --git a/core/server/api/v2/posts.js b/core/server/api/v2/posts.js index 8fe419068f8f..09f244fbfd6d 100644 --- a/core/server/api/v2/posts.js +++ b/core/server/api/v2/posts.js @@ -1,7 +1,6 @@ const models = require('../../models'); const common = require('../../lib/common'); const urlService = require('../../services/url'); -const rcUtils = require('./utils/rc-utils'); const allowedIncludes = ['tags', 'authors', 'authors.roles']; const unsafeAttrs = ['status', 'authors']; @@ -98,17 +97,11 @@ module.exports = { unsafeAttrs: unsafeAttrs }, query(frame) { - const toAnnounce = frame.data.posts[0].to_announce; - const id = frame.original.rc_uid; - const token = frame.original.rc_token; return models.Post.add(frame.data.posts[0], frame.options) .then((model) => { if (model.get('status') !== 'published') { this.headers.cacheInvalidate = false; } else { - if (toAnnounce) { - rcUtils.announcePost(id, token, model.toJSON()); - } this.headers.cacheInvalidate = true; } @@ -141,14 +134,8 @@ module.exports = { unsafeAttrs: unsafeAttrs }, query(frame) { - const toAnnounce = frame.data.posts[0].to_announce; - const id = frame.original.rc_uid; - const token = frame.original.rc_token; return models.Post.edit(frame.data.posts[0], frame.options) .then((model) => { - if (toAnnounce && model.get('status') === 'published') { - rcUtils.announcePost(id, token, model.toJSON()); - } if ( model.get('status') === 'published' && model.wasChanged() || model.get('status') === 'draft' && model.previous('status') === 'published' diff --git a/core/server/api/v2/utils/rc-utils/api.js b/core/server/api/v2/utils/rc-utils/api.js index f598406f8efe..0edf516f6aa7 100644 --- a/core/server/api/v2/utils/rc-utils/api.js +++ b/core/server/api/v2/utils/rc-utils/api.js @@ -19,10 +19,6 @@ module.exports = { return this.getRCUrl() + '/api/v1/rooms.info?' + `roomName=${roomname}`; }, - buildAnnounce() { - return this.getRCUrl() + '/api/v1/chat.postMessage'; - }, - getHeader(id, token) { return { 'X-Auth-Token': token, diff --git a/core/server/api/v2/utils/rc-utils/rc-utils.js b/core/server/api/v2/utils/rc-utils/rc-utils.js index 1b62f3349926..e14536c0b26a 100644 --- a/core/server/api/v2/utils/rc-utils/rc-utils.js +++ b/core/server/api/v2/utils/rc-utils/rc-utils.js @@ -2,7 +2,6 @@ const Promise = require('bluebird'); const request = require('request'); const common = require('../../../../lib/common'); const api = require('./api'); -const message = require('./message'); function getIdToken(req) { let id, token; @@ -145,13 +144,5 @@ module.exports = { resolve(room); }); }); - }, - - announcePost(id, token, post) { - return new Promise((resolve) => { - request.post({ url: api.buildAnnounce(), headers: api.getHeader(id, token), form: message(post) }, function (e, r, body) { - resolve(); - }); - }); } }; diff --git a/core/server/api/v2/utils/validators/input/schemas/posts.json b/core/server/api/v2/utils/validators/input/schemas/posts.json index c9041aa46b9c..4d7b40083a45 100644 --- a/core/server/api/v2/utils/validators/input/schemas/posts.json +++ b/core/server/api/v2/utils/validators/input/schemas/posts.json @@ -25,7 +25,7 @@ "type": ["string", "null"], "maxLength": 17 }, - "to_announce": { + "announce": { "type": "boolean" }, "mobiledoc": { diff --git a/core/server/data/schema/default-settings.json b/core/server/data/schema/default-settings.json index 4cbc71e0c9b5..45d02dac343b 100644 --- a/core/server/data/schema/default-settings.json +++ b/core/server/data/schema/default-settings.json @@ -110,8 +110,14 @@ "server_url": { "defaultValue": "http://localhost:4000" }, + "announce_token": { + "defaultValue": "hookid/tokentoannounce" + }, + "collaboration_token": { + "defaultValue": "hookid/tokentocollaborate" + }, "room_name": { - "defaultValue": "articles", + "defaultValue": "general", "validations": { "isLength": { "max": 150 @@ -119,7 +125,7 @@ } }, "room_id": { - "defaultValue": "ridOfAboveRoom", + "defaultValue": "GENERAL", "validations": { "isLength": { "max": 17 diff --git a/core/server/data/schema/schema.js b/core/server/data/schema/schema.js index 2319a8d51693..c5851fd7c8b3 100644 --- a/core/server/data/schema/schema.js +++ b/core/server/data/schema/schema.js @@ -23,6 +23,7 @@ module.exports = { feature_image: {type: 'string', maxlength: 2000, nullable: true}, featured: {type: 'bool', nullable: false, defaultTo: false}, page: {type: 'bool', nullable: false, defaultTo: false}, + announce: {type: 'bool', nullable: true, defaultTo: false}, status: {type: 'string', maxlength: 50, nullable: false, defaultTo: 'draft'}, locale: {type: 'string', maxlength: 6, nullable: true}, visibility: { diff --git a/core/server/index.js b/core/server/index.js index 02fe1355b3d5..b8ff9800bdc2 100644 --- a/core/server/index.js +++ b/core/server/index.js @@ -29,6 +29,7 @@ function initialiseServices() { apps = require('./services/apps'), xmlrpc = require('./services/xmlrpc'), slack = require('./services/slack'), + announcement = require('./services/announcement'); webhooks = require('./services/webhooks'), scheduling = require('./adapters/scheduling'); @@ -39,6 +40,7 @@ function initialiseServices() { permissions.init(), xmlrpc.listen(), slack.listen(), + announcement.listen(), webhooks.listen(), apps.init(), scheduling.init({ diff --git a/core/server/services/announcement.js b/core/server/services/announcement.js new file mode 100644 index 000000000000..39c1827abdcd --- /dev/null +++ b/core/server/services/announcement.js @@ -0,0 +1,82 @@ +var common = require('../lib/common'), + request = require('../lib/request'), + getMessage = require('./rcservices/message'), + settingsCache = require('./settings/cache'), + schema = require('../data/schema').checks, + + defaultPostSlugs = [ + 'welcome', + 'the-editor', + 'using-tags', + 'managing-users', + 'private-sites', + 'advanced-markdown', + 'themes' + ]; + +function getGhook() { + var rcUrl = settingsCache.get('server_url'); + var announceToken = settingsCache.get('announce_token'); + // This might one day have multiple entries, for now its always a array + // and we return the first item or an empty object + return announceToken ? `${rcUrl}/ghooks/${announceToken}` : null; +} + +function ping(post) { + let announcementData = {}, + hook = getGhook(); + + // Quit here if announcement token is not present OR user don't want to announce the post + if (hook && post.announce) { + // Only ping when not a page + if (post.page) { + return; + } + + // Don't ping for the default posts. + // This also handles the case where during ghost's first run + // models.init() inserts this post but permissions.init() hasn't + // (can't) run yet. + if (defaultPostSlugs.indexOf(post.slug) > -1) { + return; + } + + if (schema.isPost(post)) { + announcementData = getMessage(post); + } else { + announcementData = {}; + } + + return request(hook, { + body: JSON.stringify(announcementData), + headers: { + 'Content-type': 'application/json' + } + }).catch(function (err) { + common.logging.error(new common.errors.GhostError({ + err: err, + context: common.i18n.t('errors.services.ping.requestFailed.error', {service: 'announcement'}), + help: common.i18n.t('errors.services.ping.requestFailed.help', {url: 'https://docs.ghost.org'}) + })); + }); + } +} + +function listener(model, options) { + // CASE: do not ping announcement if we import a database + // TODO: refactor post.published events to never fire on importing + if (options && options.importing) { + return; + } + + ping(model.toJSON()); +} + +function listen() { + common.events.on('post.published', listener); +} + +// Public API +module.exports = { + listen: listen +}; diff --git a/core/server/api/v2/utils/rc-utils/message.js b/core/server/services/rcservices/message.js similarity index 86% rename from core/server/api/v2/utils/rc-utils/message.js rename to core/server/services/rcservices/message.js index f437455f0a55..783943ecd112 100644 --- a/core/server/api/v2/utils/rc-utils/message.js +++ b/core/server/services/rcservices/message.js @@ -1,6 +1,6 @@ -const utils = require('../../../../services/url/utils'); -const urlService = require('../../../../services/url'); -const settingsCache = require('../../../../services/settings/cache'); +const utils = require('../../services/url/utils'); +const urlService = require('../../services/url'); +const settingsCache = require('../../services/settings/cache'); function handleImageUrl(url) { return urlService.utils.urlFor('image', { image: url }, true); @@ -21,6 +21,7 @@ module.exports = (post) => { "alias": settingsCache.get('title'), "avatar": avatar, "roomId": post.room_id, + "userId": post.primary_author.rc_id, "text": `@here: @${post.primary_author.rc_username} published an article`, "attachments": [ { From 3a826b5d27ff2c1b3c9256fe386c5126bdb90390 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Tue, 11 Jun 2019 18:41:25 +0530 Subject: [PATCH 16/33] change avatar --- .../utils/validators/input/schemas/pages.json | 27 +++++++++++++++++++ core/server/services/rcservices/message.js | 3 ++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/core/server/api/v2/utils/validators/input/schemas/pages.json b/core/server/api/v2/utils/validators/input/schemas/pages.json index 4d975b118b4d..9e7486c62361 100644 --- a/core/server/api/v2/utils/validators/input/schemas/pages.json +++ b/core/server/api/v2/utils/validators/input/schemas/pages.json @@ -17,6 +17,20 @@ "type": "string", "maxLength": 191 }, + "room_name": { + "type": ["string", "null"], + "maxLength": 256 + }, + "room_id": { + "type": ["string", "null"], + "maxLength": 17 + }, + "announce": { + "type": "boolean" + }, + "to_collaborate": { + "type": "boolean" + }, "mobiledoc": { "type": ["string", "null"], "maxLength": 1000000000 @@ -99,6 +113,19 @@ "type": ["string", "null"], "maxLength": 500 }, + "rc_image": { + "type": ["string", "null"], + "format": "uri-reference", + "maxLength": 2000 + }, + "rc_title": { + "type": ["string", "null"], + "maxLength": 300 + }, + "rc_description": { + "type": ["string", "null"], + "maxLength": 500 + }, "custom_template": { "type": ["string", "null"], "maxLength": 100 diff --git a/core/server/services/rcservices/message.js b/core/server/services/rcservices/message.js index 783943ecd112..5be73a572a04 100644 --- a/core/server/services/rcservices/message.js +++ b/core/server/services/rcservices/message.js @@ -1,3 +1,4 @@ +const imageLib = require('../../lib/image'); const utils = require('../../services/url/utils'); const urlService = require('../../services/url'); const settingsCache = require('../../services/settings/cache'); @@ -7,7 +8,7 @@ function handleImageUrl(url) { } module.exports = (post) => { - const avatar = settingsCache.get('icon') ? handleImageUrl(settingsCache.get('icon')) : null; + const avatar = imageLib.blogIcon.getIconUrl(true); const blogUrl = utils.getBlogUrl(); const postUrl = `${blogUrl}/${post.slug}`; From 748e84026989e82057c56095521211ea04636bc2 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Sat, 15 Jun 2019 00:06:19 +0530 Subject: [PATCH 17/33] add missing import and fix url --- core/client | 2 +- core/server/api/v2/utils/rc-utils/rc-utils.js | 4 ++++ core/server/services/rcservices/message.js | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/core/client b/core/client index 62246592eeab..3254e76ac581 160000 --- a/core/client +++ b/core/client @@ -1 +1 @@ -Subproject commit 62246592eeabb86f5c364dde5f3db0a292f373e2 +Subproject commit 3254e76ac581f4031601efe56cdf2e9b7de1e457 diff --git a/core/server/api/v2/utils/rc-utils/rc-utils.js b/core/server/api/v2/utils/rc-utils/rc-utils.js index e14536c0b26a..f681663b86d1 100644 --- a/core/server/api/v2/utils/rc-utils/rc-utils.js +++ b/core/server/api/v2/utils/rc-utils/rc-utils.js @@ -1,5 +1,7 @@ const Promise = require('bluebird'); const request = require('request'); +const {forEach} = require('lodash'); +const models = require('../../../../models'); const common = require('../../../../lib/common'); const api = require('./api'); @@ -125,8 +127,10 @@ module.exports = { return new Promise((resolve) => { request.get({ url: api.buildRoomQuery(roomName), headers: api.getHeader(id, token) }, function (e, r, body) { let result; + if (body) result = JSON.parse(body); + if (result && result.success) { r = result.room; room = { diff --git a/core/server/services/rcservices/message.js b/core/server/services/rcservices/message.js index 5be73a572a04..b987b245b546 100644 --- a/core/server/services/rcservices/message.js +++ b/core/server/services/rcservices/message.js @@ -10,7 +10,7 @@ function handleImageUrl(url) { module.exports = (post) => { const avatar = imageLib.blogIcon.getIconUrl(true); const blogUrl = utils.getBlogUrl(); - const postUrl = `${blogUrl}/${post.slug}`; + const postUrl = `${blogUrl}${post.slug}`; let image = post.rc_image ? post.rc_image : (post.feature_image ? post.feature_image : settingsCache.get('cover_image')); let shortDescription = post.html.replace(/<[^>]*>?/gm, ' '); From 0509a44a26d07ee0932ed5daff4b5b0ca7a6f570 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Mon, 27 May 2019 21:22:14 +0530 Subject: [PATCH 18/33] add login with access_token and user_id --- core/client | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/client b/core/client index 3254e76ac581..af599a23384f 160000 --- a/core/client +++ b/core/client @@ -1 +1 @@ -Subproject commit 3254e76ac581f4031601efe56cdf2e9b7de1e457 +Subproject commit af599a23384f1afc18fe8e66e071d1b297db900d From 3f3a63b35ed478851b76404bbc6bbdbc9017d48e Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Sat, 1 Jun 2019 14:36:53 +0530 Subject: [PATCH 19/33] add redirect from rc --- core/client | 2 +- core/server/api/v2/posts.js | 96 +++++++++++++++++++ core/server/api/v2/utils/rc-users.js | 4 +- .../v2/utils/validators/utils/json-schema.js | 3 +- core/server/web/api/v2/admin/routes.js | 7 +- 5 files changed, 108 insertions(+), 4 deletions(-) diff --git a/core/client b/core/client index af599a23384f..706dbaae23d5 160000 --- a/core/client +++ b/core/client @@ -1 +1 @@ -Subproject commit af599a23384f1afc18fe8e66e071d1b297db900d +Subproject commit 706dbaae23d579d1d4f6418accae21d539abc7e6 diff --git a/core/server/api/v2/posts.js b/core/server/api/v2/posts.js index 09f244fbfd6d..c7cfb8607d5b 100644 --- a/core/server/api/v2/posts.js +++ b/core/server/api/v2/posts.js @@ -1,6 +1,7 @@ const models = require('../../models'); const common = require('../../lib/common'); const urlService = require('../../services/url'); +const rcUtils = require('./utils/rc-utils'); const allowedIncludes = ['tags', 'authors', 'authors.roles']; const unsafeAttrs = ['status', 'authors']; @@ -97,6 +98,49 @@ module.exports = { unsafeAttrs: unsafeAttrs }, query(frame) { + const toAnnounce = frame.data.posts[0].to_announce || false; + if (toAnnounce) { + const roomName = frame.data.posts[0].room_name; + if (!roomName) { + return Promise.reject(new common.errors.NotFoundError({ + message: 'Please provide a roomName to announce.' + })); + // throw new common.errors.NotFoundError({ + // message: 'Please provide a roomName to annoucne.' + // }); + } else { + let header = { + 'X-Auth-Token': 'Snhsgh5Q_q6y-ZlhGaN9AIbzN8iGCZEzfLAXNU9Y29G', + 'X-User-Id': 'AZG7dyTXMJoPhJHE7' + }; + // validate if the room is accessible by user. + return rcUtils.validateRoom('https://open.rocket.chat/api/v1/rooms.info', header, roomName) + .then((r, err) => { + if (err) { + errors.push(err); + } else if (!r || !r.exist) { + return Promise.reject(new common.errors.NotFoundError({ + message: 'Room doesnot exist. Make sure you have access to the room.' + })); + // throw new common.errors.NotFoundError({ + // message: 'Room doesnot exist. Make sure you have access to the room.' + // }); + } else if (r.name === roomName) { + frame.data.posts[0].room_id = r.rid; + } + console.log(frame.data.posts[0]) + return models.Post.add(frame.data.posts[0], frame.options) + .then((model) => { + if (model.get('status') !== 'published') { + this.headers.cacheInvalidate = false; + } else { + this.headers.cacheInvalidate = true; + } + return model; + }); + }); + } + } return models.Post.add(frame.data.posts[0], frame.options) .then((model) => { if (model.get('status') !== 'published') { @@ -134,6 +178,58 @@ module.exports = { unsafeAttrs: unsafeAttrs }, query(frame) { + const toAnnounce = frame.data.posts[0].to_announce || false; + const status = frame.data.posts[0].status; + if (toAnnounce && status === 'published') { + const roomName = frame.data.posts[0].room_name; + if (!roomName) { + return Promise.reject(new common.errors.NotFoundError({ + message: 'Please provide a roomName to announce.' + })); + } else { + let header = { + 'X-Auth-Token': 'Snhsgh5Q_q6y-ZlhGaN9AIbzN8iGCZEzfLAXNU9Y29G', + 'X-User-Id': 'AZG7dyTXMJoPhJHE7' + }; + // validate if the room is accessible by user. + return rcUtils.validateRoom('https://open.rocket.chat/api/v1/rooms.info', header, roomName) + .then((r, err) => { + if (err) { + errors.push(err); + } else if (!r || !r.exist) { + return Promise.reject(new common.errors.NotFoundError({ + message: 'Room doesnot exist. Make sure you have access to the room.' + })); + } else if (r.name === roomName) { + frame.data.posts[0].room_id = r.rid; + } + console.log(frame.data.posts[0]) + return models.Post.edit(frame.data.posts[0], frame.options) + .then((model) => { + if ( + model.get('status') === 'published' && model.wasChanged() || + model.get('status') === 'draft' && model.previous('status') === 'published' + ) { + this.headers.cacheInvalidate = true; + } else if ( + model.get('status') === 'draft' && model.previous('status') !== 'published' || + model.get('status') === 'scheduled' && model.wasChanged() + ) { + this.headers.cacheInvalidate = { + value: urlService.utils.urlFor({ + relativeUrl: urlService.utils.urlJoin('/p', model.get('uuid'), '/') + }) + }; + } else { + this.headers.cacheInvalidate = false; + } + + return model; + }); + }); + } + } + console.log(frame.data.posts[0]); return models.Post.edit(frame.data.posts[0], frame.options) .then((model) => { if ( diff --git a/core/server/api/v2/utils/rc-users.js b/core/server/api/v2/utils/rc-users.js index b6faf31c5a80..db96c7687e34 100644 --- a/core/server/api/v2/utils/rc-users.js +++ b/core/server/api/v2/utils/rc-users.js @@ -33,7 +33,9 @@ module.exports = async function getRCUsers(apiUrl, header) { }); }); } else { - throw new common.errors.InternalServerError({ message: 'Unable to add users from RC.' }); + return Promise.reject(new common.errors.InternalServerError({ + message: 'Unable to add user from RC' + })); } }); offset = 1; diff --git a/core/server/api/v2/utils/validators/utils/json-schema.js b/core/server/api/v2/utils/validators/utils/json-schema.js index b355239ddcef..cc2ee19ae9ee 100644 --- a/core/server/api/v2/utils/validators/utils/json-schema.js +++ b/core/server/api/v2/utils/validators/utils/json-schema.js @@ -21,7 +21,8 @@ const validate = (schema, definition, data) => { const validation = getValidation(schema, definition); validation(data); - + + // console.log(data); if (validation.errors) { let key; const dataPath = _.get(validation, 'errors[0].dataPath'); diff --git a/core/server/web/api/v2/admin/routes.js b/core/server/web/api/v2/admin/routes.js index 63b783732991..6c76b6e57eee 100644 --- a/core/server/web/api/v2/admin/routes.js +++ b/core/server/web/api/v2/admin/routes.js @@ -1,5 +1,6 @@ const express = require('express'); const api = require('../../../../api'); +const cors = require('cors'); const apiv2 = require('../../../../api/v2'); const mw = require('./middleware'); @@ -16,7 +17,11 @@ module.exports = function apiRoutes() { router.del = router.delete; // ## CORS pre-flight check - router.options('*', shared.middlewares.api.cors); + // router.options('*', shared.middlewares.api.cors); + + // ## Allow CORS + router.options('*', cors()); + const http = apiv2.http; From c6e47d447f2b47e205611604132926fed239d817 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Wed, 5 Jun 2019 04:39:46 +0530 Subject: [PATCH 20/33] add rcapi and improve code --- core/client | 2 +- core/server/api/v2/posts.js | 96 ----------- core/server/api/v2/utils/rc-users.js | 157 ++++++++++++------ .../api/v2/utils/serializers/output/rcapi.js | 4 +- .../v2/utils/validators/utils/json-schema.js | 3 +- core/server/web/api/v2/admin/routes.js | 7 +- 6 files changed, 107 insertions(+), 162 deletions(-) diff --git a/core/client b/core/client index 706dbaae23d5..d55e430a9f6b 160000 --- a/core/client +++ b/core/client @@ -1 +1 @@ -Subproject commit 706dbaae23d579d1d4f6418accae21d539abc7e6 +Subproject commit d55e430a9f6b31983653f0c88a99f55c0e45adf2 diff --git a/core/server/api/v2/posts.js b/core/server/api/v2/posts.js index c7cfb8607d5b..09f244fbfd6d 100644 --- a/core/server/api/v2/posts.js +++ b/core/server/api/v2/posts.js @@ -1,7 +1,6 @@ const models = require('../../models'); const common = require('../../lib/common'); const urlService = require('../../services/url'); -const rcUtils = require('./utils/rc-utils'); const allowedIncludes = ['tags', 'authors', 'authors.roles']; const unsafeAttrs = ['status', 'authors']; @@ -98,49 +97,6 @@ module.exports = { unsafeAttrs: unsafeAttrs }, query(frame) { - const toAnnounce = frame.data.posts[0].to_announce || false; - if (toAnnounce) { - const roomName = frame.data.posts[0].room_name; - if (!roomName) { - return Promise.reject(new common.errors.NotFoundError({ - message: 'Please provide a roomName to announce.' - })); - // throw new common.errors.NotFoundError({ - // message: 'Please provide a roomName to annoucne.' - // }); - } else { - let header = { - 'X-Auth-Token': 'Snhsgh5Q_q6y-ZlhGaN9AIbzN8iGCZEzfLAXNU9Y29G', - 'X-User-Id': 'AZG7dyTXMJoPhJHE7' - }; - // validate if the room is accessible by user. - return rcUtils.validateRoom('https://open.rocket.chat/api/v1/rooms.info', header, roomName) - .then((r, err) => { - if (err) { - errors.push(err); - } else if (!r || !r.exist) { - return Promise.reject(new common.errors.NotFoundError({ - message: 'Room doesnot exist. Make sure you have access to the room.' - })); - // throw new common.errors.NotFoundError({ - // message: 'Room doesnot exist. Make sure you have access to the room.' - // }); - } else if (r.name === roomName) { - frame.data.posts[0].room_id = r.rid; - } - console.log(frame.data.posts[0]) - return models.Post.add(frame.data.posts[0], frame.options) - .then((model) => { - if (model.get('status') !== 'published') { - this.headers.cacheInvalidate = false; - } else { - this.headers.cacheInvalidate = true; - } - return model; - }); - }); - } - } return models.Post.add(frame.data.posts[0], frame.options) .then((model) => { if (model.get('status') !== 'published') { @@ -178,58 +134,6 @@ module.exports = { unsafeAttrs: unsafeAttrs }, query(frame) { - const toAnnounce = frame.data.posts[0].to_announce || false; - const status = frame.data.posts[0].status; - if (toAnnounce && status === 'published') { - const roomName = frame.data.posts[0].room_name; - if (!roomName) { - return Promise.reject(new common.errors.NotFoundError({ - message: 'Please provide a roomName to announce.' - })); - } else { - let header = { - 'X-Auth-Token': 'Snhsgh5Q_q6y-ZlhGaN9AIbzN8iGCZEzfLAXNU9Y29G', - 'X-User-Id': 'AZG7dyTXMJoPhJHE7' - }; - // validate if the room is accessible by user. - return rcUtils.validateRoom('https://open.rocket.chat/api/v1/rooms.info', header, roomName) - .then((r, err) => { - if (err) { - errors.push(err); - } else if (!r || !r.exist) { - return Promise.reject(new common.errors.NotFoundError({ - message: 'Room doesnot exist. Make sure you have access to the room.' - })); - } else if (r.name === roomName) { - frame.data.posts[0].room_id = r.rid; - } - console.log(frame.data.posts[0]) - return models.Post.edit(frame.data.posts[0], frame.options) - .then((model) => { - if ( - model.get('status') === 'published' && model.wasChanged() || - model.get('status') === 'draft' && model.previous('status') === 'published' - ) { - this.headers.cacheInvalidate = true; - } else if ( - model.get('status') === 'draft' && model.previous('status') !== 'published' || - model.get('status') === 'scheduled' && model.wasChanged() - ) { - this.headers.cacheInvalidate = { - value: urlService.utils.urlFor({ - relativeUrl: urlService.utils.urlJoin('/p', model.get('uuid'), '/') - }) - }; - } else { - this.headers.cacheInvalidate = false; - } - - return model; - }); - }); - } - } - console.log(frame.data.posts[0]); return models.Post.edit(frame.data.posts[0], frame.options) .then((model) => { if ( diff --git a/core/server/api/v2/utils/rc-users.js b/core/server/api/v2/utils/rc-users.js index db96c7687e34..9c15c68e7f23 100644 --- a/core/server/api/v2/utils/rc-users.js +++ b/core/server/api/v2/utils/rc-users.js @@ -1,65 +1,112 @@ const Promise = require('bluebird'); const request = require('request'); +const settingsCache = require('../../../services/settings/cache'); const common = require('../../../lib/common'); -const models = require('../../../models'); -module.exports = async function getRCUsers(apiUrl, header) { - const options = { context: { internal: true } }; - let author_id; - models.Role.findOne({name: 'Author'}) - .then((role)=>{ - author_id = role.id; - }); - return new Promise((resolve) => { - let users, offset = 0, total = 1, count = 10; - let fetched = false; - for (offset; offset < total;) { - request.get({ url: buidApiUrl(apiUrl, offset, count), headers: header }, function (e, r, body) { - let result = JSON.parse(body); - if (result.success) { - total = result.total; - //offset += result.count; - users = result.users; - // Check if RC gives admin callee result. - // if (users && users[0] && !users[0].password) { - // throw new common.errors.InternalServerError({message: 'Doesnot have admin access in RC.'}); - // } - users.forEach(user => { - models.User.findOne({ rc_id: user._id }, options) - .then((u) => { - // Don't save if User is already in the DB. - if (!u) - saveUser(user, author_id, options); - }); - }); +function getRCUrl() { + return settingsCache.get('server_url'); +} + +function buildMeUrl(url = null) { + console.log('hrere'); + const base = url || getRCUrl(); + console.log(base); + return base + '/api/v1/me'; +} + +function buildUserQuery(username) { + return getRCUrl() + '/api/v1/users.info?' + `username=${username}`; +} + +function getHeader(id, token) { + return { + 'X-Auth-Token': token, + 'X-User-Id': id + }; +} + +module.exports = { + checkAdmin(url, id, token) { + let user; + return new Promise((resolve) => { + request.get({ url: buildMeUrl(url), headers: getHeader(id, token) }, function (e, r, body) { + user = JSON.parse(body); + if (user.success) { + if (user.roles.indexOf('admin') == -1) { + //callee is not admin on RC + return Promise.reject(new common.errors.GhostError({ + message: 'Callee is not an admin, cannot Setup Ghost' + })); + } } else { - return Promise.reject(new common.errors.InternalServerError({ - message: 'Unable to add user from RC' + return Promise.reject(new common.errors.GhostError({ + message: 'Unable to fetch the details' })); } + resolve(user); }); - offset = 1; - } - resolve(fetched); - }) -}; + }) + }, -function saveUser(user, role, options) { - // let email = user.emails[0].address; - // user.emails.foreach((e)=>{ - // if (e.verified) { - // email = e.address; - // } - // }); - return models.User.add({ - rc_id: user._id, - email: user._id + '@g.com', - name: user.name, - password: '$2a$10$etxjjsdeTbUC7aG3Od2/EuMUY4iqqXEV4jF0MtXSfsL2RmwJT3Jjm',//user.password.bcrypt, - roles: [role]// @TODO add author role_id - }, options); -} + getUser(id, token, username) { + let user; + return new Promise((resolve) => { + request.get({ url: buildUserQuery(username), headers: getHeader(id, token) }, function (e, r, body) { + let result; + if (body) + result = JSON.parse(body); + if (result && result.success) { + user = result; + } else { + user = { + success: false, + }; + } + resolve(user); + }); + }); + }, -function buidApiUrl(base, offset, count) { - return base + '?' + `offset=${offset}&count=${count}`; -} + getMe(id, token) { + let user; + return new Promise((resolve) => { + request.get({ url: buildMeUrl(), headers: getHeader(id, token) }, function (e, r, body) { + let result; + if (body) + result = JSON.parse(body); + if (result && result.success) { + user = result; + } else { + user = { + success: false, + }; + } + resolve(user); + }); + }); + }, + + validateUser(id, token, userName) { + let user; + return new Promise((resolve) => { + request.get({ url: buildUserQuery(userName), headers: getHeader(id, token) }, function (e, r, body) { + let result; + if (body) + result = JSON.parse(body); + if (result && result.success) { + u = result.user; + user = { + exist: true, + rid: u._id, + username: u.username, + }; + } else { + user = { + exist: false, + }; + } + resolve(user); + }); + }); + } +}; diff --git a/core/server/api/v2/utils/serializers/output/rcapi.js b/core/server/api/v2/utils/serializers/output/rcapi.js index 9539764bcf9f..eddd0b94eec4 100644 --- a/core/server/api/v2/utils/serializers/output/rcapi.js +++ b/core/server/api/v2/utils/serializers/output/rcapi.js @@ -7,9 +7,9 @@ module.exports = { if (!models) { return; } - console.log(models) + frame.response = { - data : [models] + rc_users: [models] }; debug(frame.response); diff --git a/core/server/api/v2/utils/validators/utils/json-schema.js b/core/server/api/v2/utils/validators/utils/json-schema.js index cc2ee19ae9ee..b355239ddcef 100644 --- a/core/server/api/v2/utils/validators/utils/json-schema.js +++ b/core/server/api/v2/utils/validators/utils/json-schema.js @@ -21,8 +21,7 @@ const validate = (schema, definition, data) => { const validation = getValidation(schema, definition); validation(data); - - // console.log(data); + if (validation.errors) { let key; const dataPath = _.get(validation, 'errors[0].dataPath'); diff --git a/core/server/web/api/v2/admin/routes.js b/core/server/web/api/v2/admin/routes.js index 6c76b6e57eee..63b783732991 100644 --- a/core/server/web/api/v2/admin/routes.js +++ b/core/server/web/api/v2/admin/routes.js @@ -1,6 +1,5 @@ const express = require('express'); const api = require('../../../../api'); -const cors = require('cors'); const apiv2 = require('../../../../api/v2'); const mw = require('./middleware'); @@ -17,11 +16,7 @@ module.exports = function apiRoutes() { router.del = router.delete; // ## CORS pre-flight check - // router.options('*', shared.middlewares.api.cors); - - // ## Allow CORS - router.options('*', cors()); - + router.options('*', shared.middlewares.api.cors); const http = apiv2.http; From 404f55b07dc19cb311e95e2a0424d5f437b16ef5 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Fri, 7 Jun 2019 04:18:08 +0530 Subject: [PATCH 21/33] add channel validation --- core/client | 2 +- core/server/api/v2/utils/rc-users.js | 36 +++++++++++++++++-- .../api/v2/utils/serializers/output/rcapi.js | 4 +-- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/core/client b/core/client index d55e430a9f6b..3e321f07629f 160000 --- a/core/client +++ b/core/client @@ -1 +1 @@ -Subproject commit d55e430a9f6b31983653f0c88a99f55c0e45adf2 +Subproject commit 3e321f07629f97da0face98d98f008186ed6dabc diff --git a/core/server/api/v2/utils/rc-users.js b/core/server/api/v2/utils/rc-users.js index 9c15c68e7f23..4470b16451a5 100644 --- a/core/server/api/v2/utils/rc-users.js +++ b/core/server/api/v2/utils/rc-users.js @@ -8,9 +8,7 @@ function getRCUrl() { } function buildMeUrl(url = null) { - console.log('hrere'); const base = url || getRCUrl(); - console.log(base); return base + '/api/v1/me'; } @@ -18,6 +16,10 @@ function buildUserQuery(username) { return getRCUrl() + '/api/v1/users.info?' + `username=${username}`; } +function buildRoomQuery(roomname) { + return getRCUrl() + '/api/v1/rooms.info?' + `roomName=${roomname}`; +} + function getHeader(id, token) { return { 'X-Auth-Token': token, @@ -96,17 +98,45 @@ module.exports = { if (result && result.success) { u = result.user; user = { + type: 'rc_users', exist: true, - rid: u._id, + uid: u._id, username: u.username, }; } else { user = { + type: 'rc_users', exist: false, }; } resolve(user); }); }); + }, + + validateRoom(id, token, roomName) { + let room; + return new Promise((resolve) => { + request.get({ url: buildRoomQuery(roomName), headers: getHeader(id, token) }, function (e, r, body) { + let result; + if (body) + result = JSON.parse(body); + if (result && result.success) { + r = result.room; + room = { + type: 'rc_rooms', + exist: true, + rid: r._id, + roomname: r.name, + }; + } else { + room = { + type: 'rc_rooms', + exist: false, + }; + } + resolve(room); + }); + }); } }; diff --git a/core/server/api/v2/utils/serializers/output/rcapi.js b/core/server/api/v2/utils/serializers/output/rcapi.js index eddd0b94eec4..9539764bcf9f 100644 --- a/core/server/api/v2/utils/serializers/output/rcapi.js +++ b/core/server/api/v2/utils/serializers/output/rcapi.js @@ -7,9 +7,9 @@ module.exports = { if (!models) { return; } - + console.log(models) frame.response = { - rc_users: [models] + data : [models] }; debug(frame.response); From b7a2445efc34fd3338cd1ee20c24779187fb74d9 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Sat, 8 Jun 2019 01:01:01 +0530 Subject: [PATCH 22/33] improve rc-utils structure and add sample message for announcement --- core/client | 2 +- core/server/api/v2/posts.js | 13 ++ core/server/api/v2/utils/rc-utils/api.js | 10 +- core/server/api/v2/utils/rc-utils/message.js | 41 ++++++ .../{rc-utils.js => rc-utils.js~HEAD} | 0 ...re and add sample message for announcement | 135 ++++++++++++++++++ 6 files changed, 197 insertions(+), 4 deletions(-) create mode 100644 core/server/api/v2/utils/rc-utils/message.js rename core/server/api/v2/utils/rc-utils/{rc-utils.js => rc-utils.js~HEAD} (100%) create mode 100644 core/server/api/v2/utils/rc-utils/rc-utils.js~a571d7202... improve rc-utils structure and add sample message for announcement diff --git a/core/client b/core/client index 3e321f07629f..af599a23384f 160000 --- a/core/client +++ b/core/client @@ -1 +1 @@ -Subproject commit 3e321f07629f97da0face98d98f008186ed6dabc +Subproject commit af599a23384f1afc18fe8e66e071d1b297db900d diff --git a/core/server/api/v2/posts.js b/core/server/api/v2/posts.js index 09f244fbfd6d..8fe419068f8f 100644 --- a/core/server/api/v2/posts.js +++ b/core/server/api/v2/posts.js @@ -1,6 +1,7 @@ const models = require('../../models'); const common = require('../../lib/common'); const urlService = require('../../services/url'); +const rcUtils = require('./utils/rc-utils'); const allowedIncludes = ['tags', 'authors', 'authors.roles']; const unsafeAttrs = ['status', 'authors']; @@ -97,11 +98,17 @@ module.exports = { unsafeAttrs: unsafeAttrs }, query(frame) { + const toAnnounce = frame.data.posts[0].to_announce; + const id = frame.original.rc_uid; + const token = frame.original.rc_token; return models.Post.add(frame.data.posts[0], frame.options) .then((model) => { if (model.get('status') !== 'published') { this.headers.cacheInvalidate = false; } else { + if (toAnnounce) { + rcUtils.announcePost(id, token, model.toJSON()); + } this.headers.cacheInvalidate = true; } @@ -134,8 +141,14 @@ module.exports = { unsafeAttrs: unsafeAttrs }, query(frame) { + const toAnnounce = frame.data.posts[0].to_announce; + const id = frame.original.rc_uid; + const token = frame.original.rc_token; return models.Post.edit(frame.data.posts[0], frame.options) .then((model) => { + if (toAnnounce && model.get('status') === 'published') { + rcUtils.announcePost(id, token, model.toJSON()); + } if ( model.get('status') === 'published' && model.wasChanged() || model.get('status') === 'draft' && model.previous('status') === 'published' diff --git a/core/server/api/v2/utils/rc-utils/api.js b/core/server/api/v2/utils/rc-utils/api.js index 0edf516f6aa7..27186e448253 100644 --- a/core/server/api/v2/utils/rc-utils/api.js +++ b/core/server/api/v2/utils/rc-utils/api.js @@ -10,15 +10,19 @@ module.exports = { const base = url || this.getRCUrl(); return base + '/api/v1/me'; }, - + buildUserQuery(username) { return this.getRCUrl() + '/api/v1/users.info?' + `username=${username}`; }, - + buildRoomQuery(roomname) { return this.getRCUrl() + '/api/v1/rooms.info?' + `roomName=${roomname}`; }, - + + buildAnnounce() { + return this.getRCUrl() + '/api/v1/chat.postMessage'; + }, + getHeader(id, token) { return { 'X-Auth-Token': token, diff --git a/core/server/api/v2/utils/rc-utils/message.js b/core/server/api/v2/utils/rc-utils/message.js new file mode 100644 index 000000000000..661b16da677f --- /dev/null +++ b/core/server/api/v2/utils/rc-utils/message.js @@ -0,0 +1,41 @@ +module.exports = (post) => { + console.log(post); + return { + "alias": post.slug, + "avatar": "http://res.guggy.com/logo_128.png", + "emoji": ":smirk:", + "roomId": post.room_id, + "text": post.title, + "attachments": [ + { + "audio_url": "http://www.w3schools.com/tags/horse.mp3", + "author_icon": "https://avatars.githubusercontent.com/u/850391?v=3", + "author_link": "https://rocket.chat/", + "author_name": "Bradley Hilton", + // "collapsed": false, + "color": "#ff0000", + "fields": [ + { + // "short": true, + "title": "Test", + "value": "Testing out something or other" + }, + { + // "short": true, + "title": "Another Test", + "value": "[Link](https://google.com/) something and this and that." + } + ], + "image_url": "http://res.guggy.com/logo_128.png", + "message_link": "https://google.com", + "text": "Yay for gruggy!", + "thumb_url": "http://res.guggy.com/logo_128.png", + "title": "Attachment Example", + "title_link": "https://youtube.com", + // "title_link_download": true, + "ts": post.updated_at, + "video_url": "http://www.w3schools.com/tags/movie.mp4" + } + ] + }; +} diff --git a/core/server/api/v2/utils/rc-utils/rc-utils.js b/core/server/api/v2/utils/rc-utils/rc-utils.js~HEAD similarity index 100% rename from core/server/api/v2/utils/rc-utils/rc-utils.js rename to core/server/api/v2/utils/rc-utils/rc-utils.js~HEAD diff --git a/core/server/api/v2/utils/rc-utils/rc-utils.js~a571d7202... improve rc-utils structure and add sample message for announcement b/core/server/api/v2/utils/rc-utils/rc-utils.js~a571d7202... improve rc-utils structure and add sample message for announcement new file mode 100644 index 000000000000..c900d200727c --- /dev/null +++ b/core/server/api/v2/utils/rc-utils/rc-utils.js~a571d7202... improve rc-utils structure and add sample message for announcement @@ -0,0 +1,135 @@ +const Promise = require('bluebird'); +const request = require('request'); +const common = require('../../../../lib/common'); +const api = require('./api'); +const message = require('./message'); + +module.exports = { + checkAdmin(url, id, token) { + let user; + return new Promise((resolve) => { + request.get({ url: api.buildMeUrl(url), headers: api.getHeader(id, token) }, function (e, r, body) { + user = JSON.parse(body); + if (user.success) { + if (user.roles.indexOf('admin') == -1) { + //callee is not admin on RC + return Promise.reject(new common.errors.GhostError({ + message: 'Callee is not an admin, cannot Setup Ghost' + })); + } + } else { + return Promise.reject(new common.errors.GhostError({ + message: 'Unable to fetch the details' + })); + } + resolve(user); + }); + }) + }, + + getUser(id, token, username) { + let user; + return new Promise((resolve) => { + request.get({ url: api.buildUserQuery(username), headers: api.getHeader(id, token) }, function (e, r, body) { + let result; + if (body) + result = JSON.parse(body); + if (result && result.success) { + user = result; + } else { + user = { + success: false, + }; + } + resolve(user); + }); + }); + }, + + getMe(id, token) { + let user; + return new Promise((resolve) => { + request.get({ url: api.buildMeUrl(), headers: api.getHeader(id, token) }, function (e, r, body) { + let result; + if (body) + result = JSON.parse(body); + if (result && result.success) { + user = result; + } else { + user = { + success: false, + }; + } + resolve(user); + }); + }); + }, + + validateUser(id, token, userName) { + let user; + return new Promise((resolve) => { + request.get({ url: api.buildUserQuery(userName), headers: api.getHeader(id, token) }, function (e, r, body) { + let result; + if (body) + result = JSON.parse(body); + if (result && result.success) { + u = result.user; + user = { + type: 'rc_users', + exist: true, + uid: u._id, + username: u.username, + }; + } else { + user = { + type: 'rc_users', + exist: false, + }; + } + resolve(user); + }); + }); + }, + + validateRoom(id, token, roomName) { + let room; + return new Promise((resolve) => { + request.get({ url: api.buildRoomQuery(roomName), headers: api.getHeader(id, token) }, function (e, r, body) { + let result; + if (body) + result = JSON.parse(body); + if (result && result.success) { + r = result.room; + room = { + type: 'rc_rooms', + exist: true, + rid: r._id, + roomname: r.name, + }; + } else { + room = { + type: 'rc_rooms', + exist: false, + }; + } + resolve(room); + }); + }); + }, + + announcePost(id, token, post) { + return new Promise((resolve) => { + request.post({ url: api.buildAnnounce(), headers: api.getHeader(id, token), form: message(post) }, function (e, r, body) { + let result; + if (body) + result = JSON.parse(body); + if (result && result.success) { + console.log('true'); + } else { + console.log('false'); + } + resolve(); + }); + }); + } +}; From f374e5e4ce6849b9003836f12f1e33b223fb4131 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Sun, 9 Jun 2019 02:10:11 +0530 Subject: [PATCH 23/33] improve rc-utils structure --- core/server/api/v2/utils/rc-utils/api.js | 8 +-- core/server/api/v2/utils/rc-utils/message.js | 58 +++++++++---------- ...re and add sample message for announcement | 8 --- 3 files changed, 32 insertions(+), 42 deletions(-) diff --git a/core/server/api/v2/utils/rc-utils/api.js b/core/server/api/v2/utils/rc-utils/api.js index 27186e448253..f598406f8efe 100644 --- a/core/server/api/v2/utils/rc-utils/api.js +++ b/core/server/api/v2/utils/rc-utils/api.js @@ -10,19 +10,19 @@ module.exports = { const base = url || this.getRCUrl(); return base + '/api/v1/me'; }, - + buildUserQuery(username) { return this.getRCUrl() + '/api/v1/users.info?' + `username=${username}`; }, - + buildRoomQuery(roomname) { return this.getRCUrl() + '/api/v1/rooms.info?' + `roomName=${roomname}`; }, - + buildAnnounce() { return this.getRCUrl() + '/api/v1/chat.postMessage'; }, - + getHeader(id, token) { return { 'X-Auth-Token': token, diff --git a/core/server/api/v2/utils/rc-utils/message.js b/core/server/api/v2/utils/rc-utils/message.js index 661b16da677f..aa93bf10bc0f 100644 --- a/core/server/api/v2/utils/rc-utils/message.js +++ b/core/server/api/v2/utils/rc-utils/message.js @@ -1,41 +1,39 @@ +const utils = require('../../../../services/url/utils'); +const urlService = require('../../../../services/url'); +const settingsCache = require('../../../../services/settings/cache'); + +function handleImageUrl(url) { + return urlService.utils.urlFor('image', { image: url }, true); +} + module.exports = (post) => { - console.log(post); + const blogUrl = utils.getBlogUrl(); + console.log(settingsCache.get('icon')); + let image = post.rc_image ? post.rc_image : (post.feature_image ? post.feature_image : settingsCache.get('cover_image')); + image = handleImageUrl(image); + const postUrl = `${blogUrl}/${post.slug}`; + let shortDescription = post.html.replace(/<[^>]*>?/gm, ' '); + shortDescription = shortDescription.length > 500 ? `${shortDescription.substring(1, 500)}...` : shortDescription; return { - "alias": post.slug, - "avatar": "http://res.guggy.com/logo_128.png", - "emoji": ":smirk:", + "alias": settingsCache.get('title'), + "avatar": handleImageUrl(settingsCache.get('icon')), "roomId": post.room_id, - "text": post.title, + "text": `@here: @${post.primary_author.rc_username} published an article`, "attachments": [ { - "audio_url": "http://www.w3schools.com/tags/horse.mp3", - "author_icon": "https://avatars.githubusercontent.com/u/850391?v=3", - "author_link": "https://rocket.chat/", - "author_name": "Bradley Hilton", - // "collapsed": false, - "color": "#ff0000", - "fields": [ - { - // "short": true, - "title": "Test", - "value": "Testing out something or other" - }, + "title": post.rc_title || post.title, + "description": post.rc_description || shortDescription, + "image_url": image, + "button_alignment": "horizontal", + "actions": [ { - // "short": true, - "title": "Another Test", - "value": "[Link](https://google.com/) something and this and that." + "type": "button", + "text": "View", + "url": postUrl, } - ], - "image_url": "http://res.guggy.com/logo_128.png", - "message_link": "https://google.com", - "text": "Yay for gruggy!", - "thumb_url": "http://res.guggy.com/logo_128.png", - "title": "Attachment Example", - "title_link": "https://youtube.com", - // "title_link_download": true, - "ts": post.updated_at, - "video_url": "http://www.w3schools.com/tags/movie.mp4" + ] } ] }; } + diff --git a/core/server/api/v2/utils/rc-utils/rc-utils.js~a571d7202... improve rc-utils structure and add sample message for announcement b/core/server/api/v2/utils/rc-utils/rc-utils.js~a571d7202... improve rc-utils structure and add sample message for announcement index c900d200727c..3b99c920046d 100644 --- a/core/server/api/v2/utils/rc-utils/rc-utils.js~a571d7202... improve rc-utils structure and add sample message for announcement +++ b/core/server/api/v2/utils/rc-utils/rc-utils.js~a571d7202... improve rc-utils structure and add sample message for announcement @@ -120,14 +120,6 @@ module.exports = { announcePost(id, token, post) { return new Promise((resolve) => { request.post({ url: api.buildAnnounce(), headers: api.getHeader(id, token), form: message(post) }, function (e, r, body) { - let result; - if (body) - result = JSON.parse(body); - if (result && result.success) { - console.log('true'); - } else { - console.log('false'); - } resolve(); }); }); From ceba1f57b50bd240f3ae8ad82049494e22570781 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Tue, 11 Jun 2019 03:47:12 +0530 Subject: [PATCH 24/33] add webhook for announcing post, remove postMessage --- core/client | 2 +- core/server/api/v2/posts.js | 13 ------------- core/server/api/v2/utils/rc-utils/api.js | 4 ---- ...re and add sample message for announcement | 9 --------- core/server/services/rcservices/message.js | 12 ++++-------- .../rcservices/message.js~HEAD} | 19 ++++++++++++------- 6 files changed, 17 insertions(+), 42 deletions(-) rename core/server/{api/v2/utils/rc-utils/message.js => services/rcservices/message.js~HEAD} (75%) diff --git a/core/client b/core/client index af599a23384f..bab5dbb6529c 160000 --- a/core/client +++ b/core/client @@ -1 +1 @@ -Subproject commit af599a23384f1afc18fe8e66e071d1b297db900d +Subproject commit bab5dbb6529c70090565b14b3ce648c11f008d1a diff --git a/core/server/api/v2/posts.js b/core/server/api/v2/posts.js index 8fe419068f8f..09f244fbfd6d 100644 --- a/core/server/api/v2/posts.js +++ b/core/server/api/v2/posts.js @@ -1,7 +1,6 @@ const models = require('../../models'); const common = require('../../lib/common'); const urlService = require('../../services/url'); -const rcUtils = require('./utils/rc-utils'); const allowedIncludes = ['tags', 'authors', 'authors.roles']; const unsafeAttrs = ['status', 'authors']; @@ -98,17 +97,11 @@ module.exports = { unsafeAttrs: unsafeAttrs }, query(frame) { - const toAnnounce = frame.data.posts[0].to_announce; - const id = frame.original.rc_uid; - const token = frame.original.rc_token; return models.Post.add(frame.data.posts[0], frame.options) .then((model) => { if (model.get('status') !== 'published') { this.headers.cacheInvalidate = false; } else { - if (toAnnounce) { - rcUtils.announcePost(id, token, model.toJSON()); - } this.headers.cacheInvalidate = true; } @@ -141,14 +134,8 @@ module.exports = { unsafeAttrs: unsafeAttrs }, query(frame) { - const toAnnounce = frame.data.posts[0].to_announce; - const id = frame.original.rc_uid; - const token = frame.original.rc_token; return models.Post.edit(frame.data.posts[0], frame.options) .then((model) => { - if (toAnnounce && model.get('status') === 'published') { - rcUtils.announcePost(id, token, model.toJSON()); - } if ( model.get('status') === 'published' && model.wasChanged() || model.get('status') === 'draft' && model.previous('status') === 'published' diff --git a/core/server/api/v2/utils/rc-utils/api.js b/core/server/api/v2/utils/rc-utils/api.js index f598406f8efe..0edf516f6aa7 100644 --- a/core/server/api/v2/utils/rc-utils/api.js +++ b/core/server/api/v2/utils/rc-utils/api.js @@ -19,10 +19,6 @@ module.exports = { return this.getRCUrl() + '/api/v1/rooms.info?' + `roomName=${roomname}`; }, - buildAnnounce() { - return this.getRCUrl() + '/api/v1/chat.postMessage'; - }, - getHeader(id, token) { return { 'X-Auth-Token': token, diff --git a/core/server/api/v2/utils/rc-utils/rc-utils.js~a571d7202... improve rc-utils structure and add sample message for announcement b/core/server/api/v2/utils/rc-utils/rc-utils.js~a571d7202... improve rc-utils structure and add sample message for announcement index 3b99c920046d..75365b2e669a 100644 --- a/core/server/api/v2/utils/rc-utils/rc-utils.js~a571d7202... improve rc-utils structure and add sample message for announcement +++ b/core/server/api/v2/utils/rc-utils/rc-utils.js~a571d7202... improve rc-utils structure and add sample message for announcement @@ -2,7 +2,6 @@ const Promise = require('bluebird'); const request = require('request'); const common = require('../../../../lib/common'); const api = require('./api'); -const message = require('./message'); module.exports = { checkAdmin(url, id, token) { @@ -115,13 +114,5 @@ module.exports = { resolve(room); }); }); - }, - - announcePost(id, token, post) { - return new Promise((resolve) => { - request.post({ url: api.buildAnnounce(), headers: api.getHeader(id, token), form: message(post) }, function (e, r, body) { - resolve(); - }); - }); } }; diff --git a/core/server/services/rcservices/message.js b/core/server/services/rcservices/message.js index b987b245b546..e73d395071b6 100644 --- a/core/server/services/rcservices/message.js +++ b/core/server/services/rcservices/message.js @@ -1,4 +1,3 @@ -const imageLib = require('../../lib/image'); const utils = require('../../services/url/utils'); const urlService = require('../../services/url'); const settingsCache = require('../../services/settings/cache'); @@ -8,19 +7,16 @@ function handleImageUrl(url) { } module.exports = (post) => { - const avatar = imageLib.blogIcon.getIconUrl(true); const blogUrl = utils.getBlogUrl(); - const postUrl = `${blogUrl}${post.slug}`; - + console.log(settingsCache.get('icon')); let image = post.rc_image ? post.rc_image : (post.feature_image ? post.feature_image : settingsCache.get('cover_image')); - let shortDescription = post.html.replace(/<[^>]*>?/gm, ' '); - image = handleImageUrl(image); + const postUrl = `${blogUrl}/${post.slug}`; + let shortDescription = post.html.replace(/<[^>]*>?/gm, ' '); shortDescription = shortDescription.length > 500 ? `${shortDescription.substring(1, 500)}...` : shortDescription; - return { "alias": settingsCache.get('title'), - "avatar": avatar, + "avatar": handleImageUrl(settingsCache.get('icon')), "roomId": post.room_id, "userId": post.primary_author.rc_id, "text": `@here: @${post.primary_author.rc_username} published an article`, diff --git a/core/server/api/v2/utils/rc-utils/message.js b/core/server/services/rcservices/message.js~HEAD similarity index 75% rename from core/server/api/v2/utils/rc-utils/message.js rename to core/server/services/rcservices/message.js~HEAD index aa93bf10bc0f..b987b245b546 100644 --- a/core/server/api/v2/utils/rc-utils/message.js +++ b/core/server/services/rcservices/message.js~HEAD @@ -1,23 +1,28 @@ -const utils = require('../../../../services/url/utils'); -const urlService = require('../../../../services/url'); -const settingsCache = require('../../../../services/settings/cache'); +const imageLib = require('../../lib/image'); +const utils = require('../../services/url/utils'); +const urlService = require('../../services/url'); +const settingsCache = require('../../services/settings/cache'); function handleImageUrl(url) { return urlService.utils.urlFor('image', { image: url }, true); } module.exports = (post) => { + const avatar = imageLib.blogIcon.getIconUrl(true); const blogUrl = utils.getBlogUrl(); - console.log(settingsCache.get('icon')); + const postUrl = `${blogUrl}${post.slug}`; + let image = post.rc_image ? post.rc_image : (post.feature_image ? post.feature_image : settingsCache.get('cover_image')); - image = handleImageUrl(image); - const postUrl = `${blogUrl}/${post.slug}`; let shortDescription = post.html.replace(/<[^>]*>?/gm, ' '); + + image = handleImageUrl(image); shortDescription = shortDescription.length > 500 ? `${shortDescription.substring(1, 500)}...` : shortDescription; + return { "alias": settingsCache.get('title'), - "avatar": handleImageUrl(settingsCache.get('icon')), + "avatar": avatar, "roomId": post.room_id, + "userId": post.primary_author.rc_id, "text": `@here: @${post.primary_author.rc_username} published an article`, "attachments": [ { From 6af7be9ddcd7f320b2970ca7f810c863bc6a3d75 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Tue, 11 Jun 2019 00:50:50 +0530 Subject: [PATCH 25/33] add collaboration def setting and validator --- .../server/api/v2/utils/validators/input/schemas/posts.json | 3 +++ core/server/data/schema/default-settings.json | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/core/server/api/v2/utils/validators/input/schemas/posts.json b/core/server/api/v2/utils/validators/input/schemas/posts.json index 4d7b40083a45..e6eaa36423b4 100644 --- a/core/server/api/v2/utils/validators/input/schemas/posts.json +++ b/core/server/api/v2/utils/validators/input/schemas/posts.json @@ -28,6 +28,9 @@ "announce": { "type": "boolean" }, + "to_collaborate": { + "type": "boolean" + }, "mobiledoc": { "type": ["string", "null"], "maxLength": 1000000000 diff --git a/core/server/data/schema/default-settings.json b/core/server/data/schema/default-settings.json index 45d02dac343b..1ca67aa12c25 100644 --- a/core/server/data/schema/default-settings.json +++ b/core/server/data/schema/default-settings.json @@ -155,6 +155,12 @@ "validations": { "isIn": [["true", "false"]] } + }, + "can_collaborate": { + "defaultValue": "false", + "validations": { + "isIn": [["true", "false"]] + } } }, "private": { From 95386c28aecca489bf007d8772306760e2c4c151 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Fri, 14 Jun 2019 00:43:51 +0530 Subject: [PATCH 26/33] add collaborate schema --- .../utils/validators/input/schemas/pages.json | 2 +- .../utils/validators/input/schemas/posts.json | 2 +- core/server/data/schema/schema.js | 1 + .../services/auth/session/middleware.js | 1 + core/server/services/rcservices/message.js | 24 ++++++++++++------- 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/core/server/api/v2/utils/validators/input/schemas/pages.json b/core/server/api/v2/utils/validators/input/schemas/pages.json index 9e7486c62361..cade751ec781 100644 --- a/core/server/api/v2/utils/validators/input/schemas/pages.json +++ b/core/server/api/v2/utils/validators/input/schemas/pages.json @@ -28,7 +28,7 @@ "announce": { "type": "boolean" }, - "to_collaborate": { + "collaborate": { "type": "boolean" }, "mobiledoc": { diff --git a/core/server/api/v2/utils/validators/input/schemas/posts.json b/core/server/api/v2/utils/validators/input/schemas/posts.json index e6eaa36423b4..6e03bfe14a3b 100644 --- a/core/server/api/v2/utils/validators/input/schemas/posts.json +++ b/core/server/api/v2/utils/validators/input/schemas/posts.json @@ -28,7 +28,7 @@ "announce": { "type": "boolean" }, - "to_collaborate": { + "collaborate": { "type": "boolean" }, "mobiledoc": { diff --git a/core/server/data/schema/schema.js b/core/server/data/schema/schema.js index c5851fd7c8b3..116a66eda913 100644 --- a/core/server/data/schema/schema.js +++ b/core/server/data/schema/schema.js @@ -24,6 +24,7 @@ module.exports = { featured: {type: 'bool', nullable: false, defaultTo: false}, page: {type: 'bool', nullable: false, defaultTo: false}, announce: {type: 'bool', nullable: true, defaultTo: false}, + collaborate: {type: 'bool', nullable: true, defaultTo: false}, status: {type: 'string', maxlength: 50, nullable: false, defaultTo: 'draft'}, locale: {type: 'string', maxlength: 6, nullable: true}, visibility: { diff --git a/core/server/services/auth/session/middleware.js b/core/server/services/auth/session/middleware.js index 34f347ec9674..5298b91fe046 100644 --- a/core/server/services/auth/session/middleware.js +++ b/core/server/services/auth/session/middleware.js @@ -30,6 +30,7 @@ const getOrigin = (req) => { let UNO_SESSIONIONA; const getSession = (req, res, next) => { + console.log(req.headers.cookie); if (!UNO_SESSIONIONA) { UNO_SESSIONIONA = session({ store: new SessionStore(models.Session), diff --git a/core/server/services/rcservices/message.js b/core/server/services/rcservices/message.js index e73d395071b6..8624c84c8bae 100644 --- a/core/server/services/rcservices/message.js +++ b/core/server/services/rcservices/message.js @@ -8,7 +8,21 @@ function handleImageUrl(url) { module.exports = (post) => { const blogUrl = utils.getBlogUrl(); - console.log(settingsCache.get('icon')); + const postUrl = `${blogUrl}${post.slug}`; + const collaborateUrl = `${blogUrl}/ghost/editor/post/${post.id}`; + let actions = [{ + "type": "button", + "text": "View", + "url": postUrl, + }]; + + if (post.collaborate) + actions.push({ + "type": "button", + "text": "Collaborate", + "url": collaborateUrl, + }); + let image = post.rc_image ? post.rc_image : (post.feature_image ? post.feature_image : settingsCache.get('cover_image')); image = handleImageUrl(image); const postUrl = `${blogUrl}/${post.slug}`; @@ -26,13 +40,7 @@ module.exports = (post) => { "description": post.rc_description || shortDescription, "image_url": image, "button_alignment": "horizontal", - "actions": [ - { - "type": "button", - "text": "View", - "url": postUrl, - } - ] + "actions": actions } ] }; From a71194351084a965a568b10e3948227f9737b68f Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Sun, 16 Jun 2019 00:27:10 +0530 Subject: [PATCH 27/33] add api to check if user can collaborate --- core/client | 2 +- core/server/api/v2/posts.js | 2 + core/server/api/v2/rcapi.js | 21 ++++ core/server/api/v2/utils/rc-utils/api.js | 4 + .../{rc-utils.js~HEAD => rc-utils.js} | 39 ++++++ ...re and add sample message for announcement | 118 ------------------ .../api/v2/utils/serializers/output/rcapi.js | 18 ++- .../services/auth/session/middleware.js | 1 - core/server/services/rcservices/message.js | 1 - core/server/web/api/v2/admin/routes.js | 1 + 10 files changed, 84 insertions(+), 123 deletions(-) rename core/server/api/v2/utils/rc-utils/{rc-utils.js~HEAD => rc-utils.js} (78%) delete mode 100644 core/server/api/v2/utils/rc-utils/rc-utils.js~a571d7202... improve rc-utils structure and add sample message for announcement diff --git a/core/client b/core/client index bab5dbb6529c..5f06abb2a281 160000 --- a/core/client +++ b/core/client @@ -1 +1 @@ -Subproject commit bab5dbb6529c70090565b14b3ce648c11f008d1a +Subproject commit 5f06abb2a281cf23e7716809acb09a90e716180b diff --git a/core/server/api/v2/posts.js b/core/server/api/v2/posts.js index 09f244fbfd6d..2f9e9d45adc5 100644 --- a/core/server/api/v2/posts.js +++ b/core/server/api/v2/posts.js @@ -134,6 +134,8 @@ module.exports = { unsafeAttrs: unsafeAttrs }, query(frame) { + console.log(frame.data.posts[0]); + console.log(frame.options); return models.Post.edit(frame.data.posts[0], frame.options) .then((model) => { if ( diff --git a/core/server/api/v2/rcapi.js b/core/server/api/v2/rcapi.js index a0301f7ce8d1..17983e9efaa6 100644 --- a/core/server/api/v2/rcapi.js +++ b/core/server/api/v2/rcapi.js @@ -35,5 +35,26 @@ module.exports = { return room; }); } + }, + + collaborate: { + options: [], + data: [ + 'collaboration' + ], + validation: { + options: { + include: ALLOWED_INCLUDES, + } + }, + permissions: false, + query(frame) { + const {rc_id, post_id, post} = frame.data.collaboration[0] + console.log(frame.data.collaboration[0]); + return rcUtils.collaborate(frame.original.rc_uid, frame.original.rc_token, rc_id, post_id, post) + .then((res) => { + return res; + }); + } } }; diff --git a/core/server/api/v2/utils/rc-utils/api.js b/core/server/api/v2/utils/rc-utils/api.js index 0edf516f6aa7..ab51dbfb73a8 100644 --- a/core/server/api/v2/utils/rc-utils/api.js +++ b/core/server/api/v2/utils/rc-utils/api.js @@ -19,6 +19,10 @@ module.exports = { return this.getRCUrl() + '/api/v1/rooms.info?' + `roomName=${roomname}`; }, + buildSubscriptionQuery(roomId) { + return this.getRCUrl() + '/api/v1/subscriptions.getOne?' + `roomId=${roomId}`; + }, + getHeader(id, token) { return { 'X-Auth-Token': token, diff --git a/core/server/api/v2/utils/rc-utils/rc-utils.js~HEAD b/core/server/api/v2/utils/rc-utils/rc-utils.js similarity index 78% rename from core/server/api/v2/utils/rc-utils/rc-utils.js~HEAD rename to core/server/api/v2/utils/rc-utils/rc-utils.js index f681663b86d1..bdcf9271842c 100644 --- a/core/server/api/v2/utils/rc-utils/rc-utils.js~HEAD +++ b/core/server/api/v2/utils/rc-utils/rc-utils.js @@ -121,6 +121,31 @@ module.exports = { }); }); }, + + collaborate(id, token, rcId, postId, posts) { + const failResult = {collaborate: false}; + + if (id !== rcId) + return failResult; + + return models.Post.findOne({ id: postId}).then((post) => { + if (!post || !post.get('collaborate')) { + return failResult; + } + return models.User.findOne({ rc_id: id }).then((user) => { + if (!user) { + return failResult; + } + return this.validateSubscription(id, token, post.get('room_id')) + .then((s) => { + if (s.exist) { + // return models.Post.edit(posts); + } + return {collaborate: s.exist}; + }); + }); + }) + }, validateRoom(id, token, roomName) { let room; @@ -148,5 +173,19 @@ module.exports = { resolve(room); }); }); + }, + + validateSubscription(id, token, roomId) { + let subscription; + return new Promise((resolve) => { + request.get({ url: api.buildSubscriptionQuery(roomId), headers: api.getHeader(id, token) }, function (e, r, body) { + let result; + if (body) + result = JSON.parse(body); + subscription = {exist: result && result.success && !!result.subscription}; + resolve(subscription); + }); + }); } + }; diff --git a/core/server/api/v2/utils/rc-utils/rc-utils.js~a571d7202... improve rc-utils structure and add sample message for announcement b/core/server/api/v2/utils/rc-utils/rc-utils.js~a571d7202... improve rc-utils structure and add sample message for announcement deleted file mode 100644 index 75365b2e669a..000000000000 --- a/core/server/api/v2/utils/rc-utils/rc-utils.js~a571d7202... improve rc-utils structure and add sample message for announcement +++ /dev/null @@ -1,118 +0,0 @@ -const Promise = require('bluebird'); -const request = require('request'); -const common = require('../../../../lib/common'); -const api = require('./api'); - -module.exports = { - checkAdmin(url, id, token) { - let user; - return new Promise((resolve) => { - request.get({ url: api.buildMeUrl(url), headers: api.getHeader(id, token) }, function (e, r, body) { - user = JSON.parse(body); - if (user.success) { - if (user.roles.indexOf('admin') == -1) { - //callee is not admin on RC - return Promise.reject(new common.errors.GhostError({ - message: 'Callee is not an admin, cannot Setup Ghost' - })); - } - } else { - return Promise.reject(new common.errors.GhostError({ - message: 'Unable to fetch the details' - })); - } - resolve(user); - }); - }) - }, - - getUser(id, token, username) { - let user; - return new Promise((resolve) => { - request.get({ url: api.buildUserQuery(username), headers: api.getHeader(id, token) }, function (e, r, body) { - let result; - if (body) - result = JSON.parse(body); - if (result && result.success) { - user = result; - } else { - user = { - success: false, - }; - } - resolve(user); - }); - }); - }, - - getMe(id, token) { - let user; - return new Promise((resolve) => { - request.get({ url: api.buildMeUrl(), headers: api.getHeader(id, token) }, function (e, r, body) { - let result; - if (body) - result = JSON.parse(body); - if (result && result.success) { - user = result; - } else { - user = { - success: false, - }; - } - resolve(user); - }); - }); - }, - - validateUser(id, token, userName) { - let user; - return new Promise((resolve) => { - request.get({ url: api.buildUserQuery(userName), headers: api.getHeader(id, token) }, function (e, r, body) { - let result; - if (body) - result = JSON.parse(body); - if (result && result.success) { - u = result.user; - user = { - type: 'rc_users', - exist: true, - uid: u._id, - username: u.username, - }; - } else { - user = { - type: 'rc_users', - exist: false, - }; - } - resolve(user); - }); - }); - }, - - validateRoom(id, token, roomName) { - let room; - return new Promise((resolve) => { - request.get({ url: api.buildRoomQuery(roomName), headers: api.getHeader(id, token) }, function (e, r, body) { - let result; - if (body) - result = JSON.parse(body); - if (result && result.success) { - r = result.room; - room = { - type: 'rc_rooms', - exist: true, - rid: r._id, - roomname: r.name, - }; - } else { - room = { - type: 'rc_rooms', - exist: false, - }; - } - resolve(room); - }); - }); - } -}; diff --git a/core/server/api/v2/utils/serializers/output/rcapi.js b/core/server/api/v2/utils/serializers/output/rcapi.js index 9539764bcf9f..c50bf38b76fd 100644 --- a/core/server/api/v2/utils/serializers/output/rcapi.js +++ b/core/server/api/v2/utils/serializers/output/rcapi.js @@ -1,8 +1,22 @@ const debug = require('ghost-ignition').debug('api:v2:utils:serializers:output:rcapi'); module.exports = { - all(models, apiConfig, frame) { - debug('all'); + browse(models, apiConfig, frame) { + debug('browse'); + + if (!models) { + return; + } + + frame.response = { + data : [models] + }; + + debug(frame.response); + }, + + collaborate(models, apiConfig, frame) { + debug('collaborate'); if (!models) { return; diff --git a/core/server/services/auth/session/middleware.js b/core/server/services/auth/session/middleware.js index 5298b91fe046..34f347ec9674 100644 --- a/core/server/services/auth/session/middleware.js +++ b/core/server/services/auth/session/middleware.js @@ -30,7 +30,6 @@ const getOrigin = (req) => { let UNO_SESSIONIONA; const getSession = (req, res, next) => { - console.log(req.headers.cookie); if (!UNO_SESSIONIONA) { UNO_SESSIONIONA = session({ store: new SessionStore(models.Session), diff --git a/core/server/services/rcservices/message.js b/core/server/services/rcservices/message.js index 8624c84c8bae..3af950f009c2 100644 --- a/core/server/services/rcservices/message.js +++ b/core/server/services/rcservices/message.js @@ -25,7 +25,6 @@ module.exports = (post) => { let image = post.rc_image ? post.rc_image : (post.feature_image ? post.feature_image : settingsCache.get('cover_image')); image = handleImageUrl(image); - const postUrl = `${blogUrl}/${post.slug}`; let shortDescription = post.html.replace(/<[^>]*>?/gm, ' '); shortDescription = shortDescription.length > 500 ? `${shortDescription.substring(1, 500)}...` : shortDescription; return { diff --git a/core/server/web/api/v2/admin/routes.js b/core/server/web/api/v2/admin/routes.js index 63b783732991..0708da0e7707 100644 --- a/core/server/web/api/v2/admin/routes.js +++ b/core/server/web/api/v2/admin/routes.js @@ -214,6 +214,7 @@ module.exports = function apiRoutes() { // ## RC Api router.get('/rcapi', mw.authAdminApi, http(apiv2.rcapi.browse)); // No need for checking persmissions + router.post('/rcapi/collaborate', mw.authAdminApi, http(apiv2.rcapi.collaborate)); // ## Redirects (JSON based) router.get('/redirects/json', mw.authAdminApi, http(apiv2.redirects.download)); From b1ce4296317c07f26a0683fe36806877c7e53ce8 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Mon, 17 Jun 2019 19:30:54 +0530 Subject: [PATCH 28/33] remove unnecessary file and collaborate user after check --- core/client | 2 +- core/server/api/v2/posts.js | 2 - core/server/api/v2/rcapi.js | 2 +- core/server/api/v2/utils/rc-utils/rc-utils.js | 47 ++++++++++++++++--- .../api/v2/utils/serializers/output/rcapi.js | 18 +------ core/server/services/rcservices/message.js | 7 ++- .../services/rcservices/message.js~HEAD | 44 ----------------- 7 files changed, 50 insertions(+), 72 deletions(-) delete mode 100644 core/server/services/rcservices/message.js~HEAD diff --git a/core/client b/core/client index 5f06abb2a281..38c5be0978d6 160000 --- a/core/client +++ b/core/client @@ -1 +1 @@ -Subproject commit 5f06abb2a281cf23e7716809acb09a90e716180b +Subproject commit 38c5be0978d61d68839dd788e2e4f9ae0f7a38cd diff --git a/core/server/api/v2/posts.js b/core/server/api/v2/posts.js index 2f9e9d45adc5..09f244fbfd6d 100644 --- a/core/server/api/v2/posts.js +++ b/core/server/api/v2/posts.js @@ -134,8 +134,6 @@ module.exports = { unsafeAttrs: unsafeAttrs }, query(frame) { - console.log(frame.data.posts[0]); - console.log(frame.options); return models.Post.edit(frame.data.posts[0], frame.options) .then((model) => { if ( diff --git a/core/server/api/v2/rcapi.js b/core/server/api/v2/rcapi.js index 17983e9efaa6..83ddfcb1322a 100644 --- a/core/server/api/v2/rcapi.js +++ b/core/server/api/v2/rcapi.js @@ -50,7 +50,7 @@ module.exports = { permissions: false, query(frame) { const {rc_id, post_id, post} = frame.data.collaboration[0] - console.log(frame.data.collaboration[0]); + return rcUtils.collaborate(frame.original.rc_uid, frame.original.rc_token, rc_id, post_id, post) .then((res) => { return res; diff --git a/core/server/api/v2/utils/rc-utils/rc-utils.js b/core/server/api/v2/utils/rc-utils/rc-utils.js index bdcf9271842c..f236ddc66f59 100644 --- a/core/server/api/v2/utils/rc-utils/rc-utils.js +++ b/core/server/api/v2/utils/rc-utils/rc-utils.js @@ -16,6 +16,33 @@ function getIdToken(req) { return { id, token }; } +function getOptions(userId) { + return { + context: + { + internal: false, + external: false, + user: userId, + api_key: null, + app: null, + integration: null, + public: false + }, + filter: '(page:false)+status:[published]', + formats: 'mobiledoc', + withRelated: ['tags', 'authors'] + }; +} + +// TODO: should get the embedded relation from client-side +function getpost(model, post, user) { + let newPost = model.toJSON(); + newPost.authors.push(user.toJSON()); + post.authors = newPost.authors; + post.tags = newPost.tags; + return post; +} + module.exports = { checkAdmin(url, id, token) { let user; @@ -122,26 +149,33 @@ module.exports = { }); }, - collaborate(id, token, rcId, postId, posts) { + // post contains the json of post without embedding the relations + collaborate(id, token, rcId, postId, post) { const failResult = {collaborate: false}; if (id !== rcId) return failResult; - return models.Post.findOne({ id: postId}).then((post) => { - if (!post || !post.get('collaborate')) { + return models.Post.findOne({ id: postId, collaborate: 1}, getOptions(post.authors[0])).then((p) => { + + if (!p) { return failResult; } + return models.User.findOne({ rc_id: id }).then((user) => { if (!user) { return failResult; } - return this.validateSubscription(id, token, post.get('room_id')) + + return this.validateSubscription(id, token, p.get('room_id')) .then((s) => { if (s.exist) { - // return models.Post.edit(posts); + return models.Post.edit(getpost(p, post, user), {id: postId}).then((p) => { + return {collaborate: true}; + }); + } else { + return failResult; } - return {collaborate: s.exist}; }); }); }) @@ -180,6 +214,7 @@ module.exports = { return new Promise((resolve) => { request.get({ url: api.buildSubscriptionQuery(roomId), headers: api.getHeader(id, token) }, function (e, r, body) { let result; + if (body) result = JSON.parse(body); subscription = {exist: result && result.success && !!result.subscription}; diff --git a/core/server/api/v2/utils/serializers/output/rcapi.js b/core/server/api/v2/utils/serializers/output/rcapi.js index c50bf38b76fd..6bbc32f9d56a 100644 --- a/core/server/api/v2/utils/serializers/output/rcapi.js +++ b/core/server/api/v2/utils/serializers/output/rcapi.js @@ -1,8 +1,8 @@ const debug = require('ghost-ignition').debug('api:v2:utils:serializers:output:rcapi'); module.exports = { - browse(models, apiConfig, frame) { - debug('browse'); + all(models, apiConfig, frame) { + debug('all'); if (!models) { return; @@ -12,20 +12,6 @@ module.exports = { data : [models] }; - debug(frame.response); - }, - - collaborate(models, apiConfig, frame) { - debug('collaborate'); - - if (!models) { - return; - } - console.log(models) - frame.response = { - data : [models] - }; - debug(frame.response); } }; diff --git a/core/server/services/rcservices/message.js b/core/server/services/rcservices/message.js index 3af950f009c2..3e6d1b625894 100644 --- a/core/server/services/rcservices/message.js +++ b/core/server/services/rcservices/message.js @@ -1,3 +1,4 @@ +const imageLib = require('../../lib/image'); const utils = require('../../services/url/utils'); const urlService = require('../../services/url'); const settingsCache = require('../../services/settings/cache'); @@ -7,6 +8,7 @@ function handleImageUrl(url) { } module.exports = (post) => { + const avatar = imageLib.blogIcon.getIconUrl(true); const blogUrl = utils.getBlogUrl(); const postUrl = `${blogUrl}${post.slug}`; const collaborateUrl = `${blogUrl}/ghost/editor/post/${post.id}`; @@ -24,12 +26,13 @@ module.exports = (post) => { }); let image = post.rc_image ? post.rc_image : (post.feature_image ? post.feature_image : settingsCache.get('cover_image')); - image = handleImageUrl(image); let shortDescription = post.html.replace(/<[^>]*>?/gm, ' '); + + image = handleImageUrl(image); shortDescription = shortDescription.length > 500 ? `${shortDescription.substring(1, 500)}...` : shortDescription; return { "alias": settingsCache.get('title'), - "avatar": handleImageUrl(settingsCache.get('icon')), + "avatar": avatar, "roomId": post.room_id, "userId": post.primary_author.rc_id, "text": `@here: @${post.primary_author.rc_username} published an article`, diff --git a/core/server/services/rcservices/message.js~HEAD b/core/server/services/rcservices/message.js~HEAD deleted file mode 100644 index b987b245b546..000000000000 --- a/core/server/services/rcservices/message.js~HEAD +++ /dev/null @@ -1,44 +0,0 @@ -const imageLib = require('../../lib/image'); -const utils = require('../../services/url/utils'); -const urlService = require('../../services/url'); -const settingsCache = require('../../services/settings/cache'); - -function handleImageUrl(url) { - return urlService.utils.urlFor('image', { image: url }, true); -} - -module.exports = (post) => { - const avatar = imageLib.blogIcon.getIconUrl(true); - const blogUrl = utils.getBlogUrl(); - const postUrl = `${blogUrl}${post.slug}`; - - let image = post.rc_image ? post.rc_image : (post.feature_image ? post.feature_image : settingsCache.get('cover_image')); - let shortDescription = post.html.replace(/<[^>]*>?/gm, ' '); - - image = handleImageUrl(image); - shortDescription = shortDescription.length > 500 ? `${shortDescription.substring(1, 500)}...` : shortDescription; - - return { - "alias": settingsCache.get('title'), - "avatar": avatar, - "roomId": post.room_id, - "userId": post.primary_author.rc_id, - "text": `@here: @${post.primary_author.rc_username} published an article`, - "attachments": [ - { - "title": post.rc_title || post.title, - "description": post.rc_description || shortDescription, - "image_url": image, - "button_alignment": "horizontal", - "actions": [ - { - "type": "button", - "text": "View", - "url": postUrl, - } - ] - } - ] - }; -} - From 58699f53fd6b9016acde20c611dfcdc6cdef9856 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Tue, 18 Jun 2019 00:53:37 +0530 Subject: [PATCH 29/33] check setting while collaborating --- core/client | 2 +- core/server/api/v2/utils/rc-utils/rc-utils.js | 3 ++- core/server/services/rcservices/message.js | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/core/client b/core/client index 38c5be0978d6..2438cb7e82e8 160000 --- a/core/client +++ b/core/client @@ -1 +1 @@ -Subproject commit 38c5be0978d61d68839dd788e2e4f9ae0f7a38cd +Subproject commit 2438cb7e82e83e287319c63213e57ddc1cb58ef7 diff --git a/core/server/api/v2/utils/rc-utils/rc-utils.js b/core/server/api/v2/utils/rc-utils/rc-utils.js index f236ddc66f59..b7f6b5d9efee 100644 --- a/core/server/api/v2/utils/rc-utils/rc-utils.js +++ b/core/server/api/v2/utils/rc-utils/rc-utils.js @@ -3,6 +3,7 @@ const request = require('request'); const {forEach} = require('lodash'); const models = require('../../../../models'); const common = require('../../../../lib/common'); +const settingsCache = require('../../../../services/settings/cache'); const api = require('./api'); function getIdToken(req) { @@ -153,7 +154,7 @@ module.exports = { collaborate(id, token, rcId, postId, post) { const failResult = {collaborate: false}; - if (id !== rcId) + if (id !== rcId || !settingsCache.get('can_collaborate')) return failResult; return models.Post.findOne({ id: postId, collaborate: 1}, getOptions(post.authors[0])).then((p) => { diff --git a/core/server/services/rcservices/message.js b/core/server/services/rcservices/message.js index 3e6d1b625894..bbeb259ae6ac 100644 --- a/core/server/services/rcservices/message.js +++ b/core/server/services/rcservices/message.js @@ -11,7 +11,7 @@ module.exports = (post) => { const avatar = imageLib.blogIcon.getIconUrl(true); const blogUrl = utils.getBlogUrl(); const postUrl = `${blogUrl}${post.slug}`; - const collaborateUrl = `${blogUrl}/ghost/editor/post/${post.id}`; + const collaborateUrl = `${blogUrl}ghost/editor/post/${post.id}`; let actions = [{ "type": "button", "text": "View", From b1c86344cb51be19922958f48fd8727145a9cba4 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Tue, 18 Jun 2019 01:34:24 +0530 Subject: [PATCH 30/33] check setting while collaborating --- core/server/api/v2/utils/rc-utils/rc-utils.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/core/server/api/v2/utils/rc-utils/rc-utils.js b/core/server/api/v2/utils/rc-utils/rc-utils.js index b7f6b5d9efee..a3e71f601c5d 100644 --- a/core/server/api/v2/utils/rc-utils/rc-utils.js +++ b/core/server/api/v2/utils/rc-utils/rc-utils.js @@ -154,12 +154,9 @@ module.exports = { collaborate(id, token, rcId, postId, post) { const failResult = {collaborate: false}; - if (id !== rcId || !settingsCache.get('can_collaborate')) - return failResult; - return models.Post.findOne({ id: postId, collaborate: 1}, getOptions(post.authors[0])).then((p) => { - - if (!p) { + + if (!p || id !== rcId || !settingsCache.get('can_collaborate')) { return failResult; } From 5a6cdb878c199bd81810c12ab86f5c76179526fb Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Fri, 21 Jun 2019 03:02:11 +0530 Subject: [PATCH 31/33] fix an issue in client --- core/client | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/client b/core/client index 2438cb7e82e8..522140c35cc4 160000 --- a/core/client +++ b/core/client @@ -1 +1 @@ -Subproject commit 2438cb7e82e83e287319c63213e57ddc1cb58ef7 +Subproject commit 522140c35cc4575cff725bb0837008fc59ac8202 From 84a694243a23d4762c1270ea4174a77a7dc3194b Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Fri, 21 Jun 2019 06:26:28 +0530 Subject: [PATCH 32/33] bump to new commit client --- core/client | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/client b/core/client index 522140c35cc4..6eb00ffce423 160000 --- a/core/client +++ b/core/client @@ -1 +1 @@ -Subproject commit 522140c35cc4575cff725bb0837008fc59ac8202 +Subproject commit 6eb00ffce423603258cdecca8a612768796b4d24 From 69efabba9ca36c191668df9bc81fe76e5ce3a7e4 Mon Sep 17 00:00:00 2001 From: shubhsherl Date: Fri, 21 Jun 2019 07:02:32 +0530 Subject: [PATCH 33/33] remove invite model --- core/client | 2 +- core/server/api/v2/index.js | 4 - core/server/api/v2/invites.js | 176 ------------------ .../api/v2/utils/serializers/output/index.js | 4 - .../v2/utils/serializers/output/invites.js | 26 --- .../api/v2/utils/validators/input/index.js | 4 - .../api/v2/utils/validators/input/invites.js | 16 -- core/server/data/schema/schema.js | 18 -- core/server/models/index.js | 1 - core/server/models/invite.js | 107 ----------- core/server/services/permissions/can-this.js | 2 +- core/server/web/api/v2/admin/routes.js | 16 +- 12 files changed, 6 insertions(+), 370 deletions(-) delete mode 100644 core/server/api/v2/invites.js delete mode 100644 core/server/api/v2/utils/serializers/output/invites.js delete mode 100644 core/server/api/v2/utils/validators/input/invites.js delete mode 100644 core/server/models/invite.js diff --git a/core/client b/core/client index 6eb00ffce423..317298465ed3 160000 --- a/core/client +++ b/core/client @@ -1 +1 @@ -Subproject commit 6eb00ffce423603258cdecca8a612768796b4d24 +Subproject commit 317298465ed3189600c5420512faeb47a1fe86bf diff --git a/core/server/api/v2/index.js b/core/server/api/v2/index.js index 5a99230ee1b3..adf9ecacb519 100644 --- a/core/server/api/v2/index.js +++ b/core/server/api/v2/index.js @@ -43,10 +43,6 @@ module.exports = { return shared.pipeline(require('./posts'), localUtils); }, - get invites() { - return shared.pipeline(require('./invites'), localUtils); - }, - get rcapi() { return shared.pipeline(require('./rcapi'), localUtils); }, diff --git a/core/server/api/v2/invites.js b/core/server/api/v2/invites.js deleted file mode 100644 index 4b913bed77ba..000000000000 --- a/core/server/api/v2/invites.js +++ /dev/null @@ -1,176 +0,0 @@ -const Promise = require('bluebird'); -const common = require('../../lib/common'); -const security = require('../../lib/security'); -const mailService = require('../../services/mail'); -const urlService = require('../../services/url'); -const settingsCache = require('../../services/settings/cache'); -const models = require('../../models'); -const api = require('./index'); -const ALLOWED_INCLUDES = []; -const UNSAFE_ATTRS = ['role_id']; - -module.exports = { - docName: 'invites', - - browse: { - options: [ - 'include', - 'page', - 'limit', - 'fields', - 'filter', - 'order', - 'debug' - ], - validation: { - options: { - include: ALLOWED_INCLUDES - } - }, - permissions: true, - query(frame) { - return models.Invite.findPage(frame.options); - } - }, - - read: { - options: [ - 'include' - ], - data: [ - 'id', - 'email' - ], - validation: { - options: { - include: ALLOWED_INCLUDES - } - }, - permissions: true, - query(frame) { - return models.Invite.findOne(frame.data, frame.options) - .then((model) => { - if (!model) { - return Promise.reject(new common.errors.NotFoundError({ - message: common.i18n.t('errors.api.invites.inviteNotFound') - })); - } - - return model; - }); - } - }, - - destroy: { - statusCode: 204, - options: [ - 'include', - 'id' - ], - validation: { - options: { - include: ALLOWED_INCLUDES - } - }, - permissions: true, - query(frame) { - frame.options.require = true; - - return models.Invite.destroy(frame.options) - .return(null); - } - }, - - add: { - statusCode: 201, - options: [ - 'include', - 'email' - ], - validation: { - options: { - include: ALLOWED_INCLUDES - }, - data: { - role_id: { - required: true - }, - email: { - required: true - } - } - }, - permissions: { - unsafeAttrs: UNSAFE_ATTRS - }, - query(frame) { - let invite; - let emailData; - - // CASE: ensure we destroy the invite before - return models.Invite.findOne({email: frame.data.invites[0].email}, frame.options) - .then((invite) => { - if (!invite) { - return; - } - - return invite.destroy(frame.options); - }) - .then(() => { - return models.Invite.add(frame.data.invites[0], frame.options); - }) - .then((_invite) => { - invite = _invite; - - const adminUrl = urlService.utils.urlFor('admin', true); - - emailData = { - blogName: settingsCache.get('title'), - invitedByName: frame.user.get('name'), - invitedByEmail: frame.user.get('email'), - resetLink: urlService.utils.urlJoin(adminUrl, 'signup', security.url.encodeBase64(invite.get('token')), '/') - }; - - return mailService.utils.generateContent({data: emailData, template: 'invite-user'}); - }) - .then((emailContent) => { - const payload = { - mail: [{ - message: { - to: invite.get('email'), - subject: common.i18n.t('common.api.users.mail.invitedByName', { - invitedByName: emailData.invitedByName, - blogName: emailData.blogName - }), - html: emailContent.html, - text: emailContent.text - }, - options: {} - }] - }; - - return api.mail.send(payload, {context: {internal: true}}); - }) - .then(() => { - return models.Invite.edit({ - status: 'sent' - }, Object.assign({id: invite.id}, frame.options)); - }) - .then((invite) => { - return invite; - }) - .catch((err) => { - if (err && err.errorType === 'EmailError') { - const errorMessage = common.i18n.t('errors.api.invites.errorSendingEmail.error', { - message: err.message - }); - const helpText = common.i18n.t('errors.api.invites.errorSendingEmail.help'); - err.message = `${errorMessage} ${helpText}`; - common.logging.warn(err.message); - } - - return Promise.reject(err); - }); - } - } -}; diff --git a/core/server/api/v2/utils/serializers/output/index.js b/core/server/api/v2/utils/serializers/output/index.js index 5ddf4c612ee6..bf0018637ab5 100644 --- a/core/server/api/v2/utils/serializers/output/index.js +++ b/core/server/api/v2/utils/serializers/output/index.js @@ -35,10 +35,6 @@ module.exports = { return require('./posts'); }, - get invites() { - return require('./invites'); - }, - get rcapi() { return require('./rcapi'); }, diff --git a/core/server/api/v2/utils/serializers/output/invites.js b/core/server/api/v2/utils/serializers/output/invites.js deleted file mode 100644 index 290cb24d52f5..000000000000 --- a/core/server/api/v2/utils/serializers/output/invites.js +++ /dev/null @@ -1,26 +0,0 @@ -const debug = require('ghost-ignition').debug('api:v2:utils:serializers:output:invites'); - -module.exports = { - all(models, apiConfig, frame) { - debug('all'); - - if (!models) { - return; - } - - if (models.meta) { - frame.response = { - invites: models.data.map(model => model.toJSON(frame.options)), - meta: models.meta - }; - - return; - } - - frame.response = { - invites: [models.toJSON(frame.options)] - }; - - debug(frame.response); - } -}; diff --git a/core/server/api/v2/utils/validators/input/index.js b/core/server/api/v2/utils/validators/input/index.js index 6ad410c15ad9..9e7d26b8146d 100644 --- a/core/server/api/v2/utils/validators/input/index.js +++ b/core/server/api/v2/utils/validators/input/index.js @@ -7,10 +7,6 @@ module.exports = { return require('./pages'); }, - get invites() { - return require('./invites'); - }, - get settings() { return require('./settings'); }, diff --git a/core/server/api/v2/utils/validators/input/invites.js b/core/server/api/v2/utils/validators/input/invites.js deleted file mode 100644 index b18f71d84c31..000000000000 --- a/core/server/api/v2/utils/validators/input/invites.js +++ /dev/null @@ -1,16 +0,0 @@ -const Promise = require('bluebird'); -const common = require('../../../../../lib/common'); -const models = require('../../../../../models'); - -module.exports = { - add(apiConfig, frame) { - return models.User.findOne({email: frame.data.invites[0].email}, frame.options) - .then((user) => { - if (user) { - return Promise.reject(new common.errors.ValidationError({ - message: common.i18n.t('errors.api.users.userAlreadyRegistered') - })); - } - }); - } -}; diff --git a/core/server/data/schema/schema.js b/core/server/data/schema/schema.js index 116a66eda913..c807b16b35b0 100644 --- a/core/server/data/schema/schema.js +++ b/core/server/data/schema/schema.js @@ -293,24 +293,6 @@ module.exports = { updated_at: {type: 'dateTime', nullable: true}, updated_by: {type: 'string', maxlength: 24, nullable: true} }, - invites: { - id: {type: 'string', maxlength: 24, nullable: false, primary: true}, - role_id: {type: 'string', maxlength: 24, nullable: false}, - status: { - type: 'string', - maxlength: 50, - nullable: false, - defaultTo: 'pending', - validations: {isIn: [['pending', 'sent']]} - }, - token: {type: 'string', maxlength: 191, nullable: false, unique: true}, - email: {type: 'string', maxlength: 191, nullable: false, unique: true, validations: {isEmail: true}}, - expires: {type: 'bigInteger', nullable: false}, - created_at: {type: 'dateTime', nullable: false}, - created_by: {type: 'string', maxlength: 24, nullable: false}, - updated_at: {type: 'dateTime', nullable: true}, - updated_by: {type: 'string', maxlength: 24, nullable: true} - }, brute: { key: {type: 'string', maxlength: 191}, firstRequest: {type: 'bigInteger'}, diff --git a/core/server/models/index.js b/core/server/models/index.js index a4a33e20a1c7..80e6cb800f6a 100644 --- a/core/server/models/index.js +++ b/core/server/models/index.js @@ -32,7 +32,6 @@ models = [ 'tag-public', 'user', 'author', - 'invite', 'webhook', 'integration', 'api-key', diff --git a/core/server/models/invite.js b/core/server/models/invite.js deleted file mode 100644 index 0ad5db26eda0..000000000000 --- a/core/server/models/invite.js +++ /dev/null @@ -1,107 +0,0 @@ -const Promise = require('bluebird'); -const _ = require('lodash'); -const common = require('../lib/common'); -const constants = require('../lib/constants'); -const security = require('../lib/security'); -const settingsCache = require('../services/settings/cache'); -const ghostBookshelf = require('./base'); - -let Invite, - Invites; - -Invite = ghostBookshelf.Model.extend({ - tableName: 'invites', - - toJSON: function (unfilteredOptions) { - var options = Invite.filterOptions(unfilteredOptions, 'toJSON'), - attrs = ghostBookshelf.Model.prototype.toJSON.call(this, options); - - delete attrs.token; - return attrs; - } -}, { - orderDefaultOptions: function orderDefaultOptions() { - return {}; - }, - - add: function add(data, unfilteredOptions) { - const options = Invite.filterOptions(unfilteredOptions, 'add'); - data = data || {}; - - if (!options.context || !options.context.internal) { - data.status = 'pending'; - } - - data.expires = Date.now() + constants.ONE_WEEK_MS; - data.token = security.tokens.generateFromEmail({ - email: data.email, - expires: data.expires, - secret: settingsCache.get('db_hash') - }); - - return ghostBookshelf.Model.add.call(this, data, options); - }, - - permissible(inviteModel, action, context, unsafeAttrs, loadedPermissions, hasUserPermission, hasAppPermission, hasApiKeyPermission) { - const isAdd = (action === 'add'); - - if (!isAdd) { - if (hasUserPermission && hasAppPermission && hasApiKeyPermission) { - return Promise.resolve(); - } - - return Promise.reject(new common.errors.NoPermissionError({ - message: common.i18n.t('errors.models.invite.notEnoughPermission') - })); - } - - // CASE: make sure user is allowed to add a user with this role - return ghostBookshelf.model('Role') - .findOne({id: unsafeAttrs.role_id}) - .then((roleToInvite) => { - if (!roleToInvite) { - return Promise.reject(new common.errors.NotFoundError({ - message: common.i18n.t('errors.api.invites.roleNotFound') - })); - } - - if (roleToInvite.get('name') === 'Owner') { - return Promise.reject(new common.errors.NoPermissionError({ - message: common.i18n.t('errors.api.invites.notAllowedToInviteOwner') - })); - } - - let allowed = []; - - if (_.some(loadedPermissions.user.roles, {name: 'Owner'}) || - _.some(loadedPermissions.user.roles, {name: 'Administrator'})) { - allowed = ['Administrator', 'Editor', 'Author', 'Contributor']; - } else if (_.some(loadedPermissions.user.roles, {name: 'Editor'})) { - allowed = ['Author', 'Contributor']; - } - - if (allowed.indexOf(roleToInvite.get('name')) === -1) { - throw new common.errors.NoPermissionError({ - message: common.i18n.t('errors.api.invites.notAllowedToInvite') - }); - } - - if (hasUserPermission && hasAppPermission && hasApiKeyPermission) { - return Promise.resolve(); - } - - return Promise.reject(new common.errors.NoPermissionError({ - message: common.i18n.t('errors.models.invite.notEnoughPermission') - })); - }); - } -}); - -Invites = ghostBookshelf.Collection.extend({ - model: Invite -}); - -module.exports = { - Invite: ghostBookshelf.model('Invite', Invite), - Invites: ghostBookshelf.collection('Invites', Invites) -}; diff --git a/core/server/services/permissions/can-this.js b/core/server/services/permissions/can-this.js index e53d2835924c..8f70805eb0d8 100644 --- a/core/server/services/permissions/can-this.js +++ b/core/server/services/permissions/can-this.js @@ -20,7 +20,7 @@ CanThisResult.prototype.buildObjectTypeHandlers = function (objTypes, actType, c permission: models.Permission, setting: models.Settings, subscriber: models.Subscriber, - invite: models.Invite + // invite: models.Invite }; // Iterate through the object types, i.e. ['post', 'tag', 'user'] diff --git a/core/server/web/api/v2/admin/routes.js b/core/server/web/api/v2/admin/routes.js index 0708da0e7707..4e3e1712fd43 100644 --- a/core/server/web/api/v2/admin/routes.js +++ b/core/server/web/api/v2/admin/routes.js @@ -184,15 +184,7 @@ module.exports = function apiRoutes() { router.del('/session', mw.authAdminApi, api.http(apiv2.session.delete)); // ## Authentication - router.post('/authentication/passwordreset', - shared.middlewares.brute.globalReset, - shared.middlewares.brute.userReset, - api.http(api.authentication.generateResetToken) - ); - router.put('/authentication/passwordreset', shared.middlewares.brute.globalBlock, api.http(api.authentication.resetPassword)); - router.post('/authentication/invitation', api.http(api.authentication.acceptInvitation)); router.post('/authentication/adduser', api.http(api.authentication.addUser)); - router.get('/authentication/invitation', api.http(api.authentication.isInvitation)); router.post('/authentication/setup', api.http(api.authentication.setup)); router.put('/authentication/setup', mw.authAdminApi, api.http(api.authentication.updateSetup)); router.get('/authentication/setup', api.http(api.authentication.isSetup)); @@ -207,10 +199,10 @@ module.exports = function apiRoutes() { ); // ## Invites - router.get('/invites', mw.authAdminApi, http(apiv2.invites.browse)); - router.get('/invites/:id', mw.authAdminApi, http(apiv2.invites.read)); - router.post('/invites', mw.authAdminApi, http(apiv2.invites.add)); - router.del('/invites/:id', mw.authAdminApi, http(apiv2.invites.destroy)); + // router.get('/invites', mw.authAdminApi, http(apiv2.invites.browse)); + // router.get('/invites/:id', mw.authAdminApi, http(apiv2.invites.read)); + // router.post('/invites', mw.authAdminApi, http(apiv2.invites.add)); + // router.del('/invites/:id', mw.authAdminApi, http(apiv2.invites.destroy)); // ## RC Api router.get('/rcapi', mw.authAdminApi, http(apiv2.rcapi.browse)); // No need for checking persmissions