Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GSoC19] Rc articles syncdb #5

Open
wants to merge 22 commits into
base: rc_articles
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/client
17 changes: 16 additions & 1 deletion core/server/api/shared/http.js
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -18,6 +19,19 @@ const http = (apiImpl) => {
let apiKey = null;
let integration = null;
let user = null;
let rcUid = null;
let rcToken = null;

if (req.headers && req.headers.cookie) {
_.forEach(req.headers.cookie.split(';'), (v) => {
if (v.includes('rc_uid')) {
rcUid = v.split('=')[1];
}
if (v.includes('rc_token')) {
rcToken = v.split('=')[1];
}
});
}

if (req.api_key) {
apiKey = {
Expand All @@ -39,6 +53,8 @@ const http = (apiImpl) => {
file: req.file,
files: req.files,
query: req.query,
rc_uid: rcUid,
rc_token: rcToken,
params: req.params,
user: req.user,
context: {
Expand Down Expand Up @@ -93,7 +109,6 @@ const http = (apiImpl) => {
docName: frame.docName,
method: frame.method
};

next(err);
});
};
Expand Down
120 changes: 112 additions & 8 deletions core/server/api/v0.1/authentication.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
Expand Down Expand Up @@ -61,14 +62,25 @@ 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;
const announceToken = setupData.setup[0].announce_token;
const settingsToken = setupData.setup[0].settings_token;
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,
announce_token: announceToken,
settings_token: settingsToken,
serverUrl: rcUrl,
status: 'active'
};
});
Expand Down Expand Up @@ -97,6 +109,9 @@ function setupTasks(setupData) {
function doSettings(data) {
const user = data.user,
blogTitle = data.userData.blogTitle,
serverUrl = data.userData.serverUrl,
announceToken = data.userData.announce_token,
settingsToken = data.userData.settings_token,
context = {context: {user: data.user.id}};

let userSettings;
Expand All @@ -106,7 +121,10 @@ function setupTasks(setupData) {
}

userSettings = [
{key: 'server_url', value: serverUrl},
{key: 'title', value: blogTitle.trim()},
{key: 'announce_token', value: announceToken},
{key: 'settings_token', value: settingsToken},
{key: 'description', value: common.i18n.t('common.api.authentication.sampleBlogDescription')}
];

Expand Down Expand Up @@ -437,6 +455,91 @@ authentication = {
return pipeline(tasks, invitation);
},

/**
* ### Add Users
* @param {Object} invitation an invitation object
* @returns {Promise<Object>}
*/
addUser(invitation, option) {
let tasks;
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 rcUid = option.rc_uid || invitation.user[0].rc_uid;
const rcToken = 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(rcUid, rcToken)
.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: rcUid, 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];
return rcUtils.getUser(rcUid, rcToken, 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
Expand Down Expand Up @@ -513,7 +616,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<Object>} a user api payload
*/
Expand Down Expand Up @@ -566,7 +669,8 @@ authentication = {
tasks = [
assertSetupCompleted(false),
doSetup,
sendNotification,
// TODO: add mail service from RC.
// sendNotification,
formatResponse
];

Expand Down
13 changes: 12 additions & 1 deletion core/server/api/v0.1/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -272,6 +272,17 @@ 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;
}
Expand Down
8 changes: 8 additions & 0 deletions core/server/api/v2/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ module.exports = {
return shared.pipeline(require('./invites'), localUtils);
},

get rcapi() {
return shared.pipeline(require('./rcapi'), localUtils);
},

get rhooks() {
return shared.pipeline(require('./rhooks'), localUtils);
},

get mail() {
return shared.pipeline(require('./mail'), localUtils);
},
Expand Down
19 changes: 18 additions & 1 deletion core/server/api/v2/posts.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,24 @@ module.exports = {
message: common.i18n.t('errors.api.posts.postNotFound')
});
}

let rid = model.get('room_id');
if (rid) {
return models.Room.findOne({rid: rid}).then((r) => {
if (r) {
model.attributes.room_name = r.get('name');
}
rid = model.get('discussion_room_id');
if (rid) {
return models.Room.findOne({rid: rid}).then((d) => {
if (d) {
model.attributes.discussion_room_name = d.get('name');
}
return model;
});
}
return model;
});
}
return model;
});
}
Expand Down
59 changes: 59 additions & 0 deletions core/server/api/v2/rcapi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
const rcUtils = require('./utils/rc-utils');
const ALLOWED_INCLUDES = [];

module.exports = {
docName: 'rcapi',

browse: {
options: [
'include',
'uname',
'rname',
'page',
'limit',
'fields',
'filter',
'order',
'debug'
],
validation: {
options: {
include: ALLOWED_INCLUDES
}
},
permissions: false,
query(frame) {
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;
});
}
},

discussion: {
options: [],
data: ['room'],
validation: {
options: {
include: ALLOWED_INCLUDES
}
},
permissions: false,
query(frame) {
const username = frame.user.get('rc_username');
const {title, type} = frame.data.room[0];
return rcUtils.createDiscussion(frame.original.rc_uid, frame.original.rc_token, title, username, type)
.then((room) => {
return room;
});
}
}
};
Loading