forked from RocketChat/Rocket.Chat
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* articles commits sqashed in one * fix import error
- Loading branch information
1 parent
4b99331
commit 62fca65
Showing
31 changed files
with
871 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Readme file for articles. |
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import { Restivus } from 'meteor/nimble:restivus'; | ||
import _ from 'underscore'; | ||
|
||
import { processWebhookMessage } from '../../../lib'; | ||
import { API } from '../../../api'; | ||
import { settings } from '../../../settings'; | ||
import * as Models from '../../../models'; | ||
|
||
const Api = new Restivus({ | ||
enableCors: true, | ||
apiPath: 'ghooks/', | ||
auth: { | ||
user() { | ||
const payloadKeys = Object.keys(this.bodyParams); | ||
const payloadIsWrapped = (this.bodyParams && this.bodyParams.payload) && payloadKeys.length === 1; | ||
if (payloadIsWrapped && this.request.headers['content-type'] === 'application/x-www-form-urlencoded') { | ||
try { | ||
this.bodyParams = JSON.parse(this.bodyParams.payload); | ||
} catch ({ message }) { | ||
return { | ||
error: { | ||
statusCode: 400, | ||
body: { | ||
success: false, | ||
error: message, | ||
}, | ||
}, | ||
}; | ||
} | ||
} | ||
|
||
this.announceToken = settings.get('Announcement_Token'); | ||
const { blogId } = this.request.params; | ||
const token = decodeURIComponent(this.request.params.token); | ||
|
||
if (this.announceToken !== `${ blogId }/${ token }`) { | ||
return { | ||
error: { | ||
statusCode: 404, | ||
body: { | ||
success: false, | ||
error: 'Invalid token provided.', | ||
}, | ||
}, | ||
}; | ||
} | ||
|
||
const user = this.bodyParams.userId ? Models.Users.findOne({ _id: this.bodyParams.userId }) : Models.Users.findOne({ username: this.bodyParams.username }); | ||
|
||
return { user }; | ||
}, | ||
}, | ||
}); | ||
|
||
function executeAnnouncementRest() { | ||
const defaultValues = { | ||
channel: this.bodyParams.channel, | ||
alias: this.bodyParams.alias, | ||
avatar: this.bodyParams.avatar, | ||
emoji: this.bodyParams.emoji, | ||
}; | ||
|
||
// TODO: Turn this into an option on the integrations - no body means a success | ||
// TODO: Temporary fix for https://github.com/RocketChat/Rocket.Chat/issues/7770 until the above is implemented | ||
if (!this.bodyParams || (_.isEmpty(this.bodyParams) && !this.integration.scriptEnabled)) { | ||
// return RocketChat.API.v1.failure('body-empty'); | ||
return API.v1.success(); | ||
} | ||
|
||
try { | ||
const message = processWebhookMessage(this.bodyParams, this.user, defaultValues); | ||
if (_.isEmpty(message)) { | ||
return API.v1.failure('unknown-error'); | ||
} | ||
|
||
return API.v1.success(); | ||
} catch ({ error, message }) { | ||
return API.v1.failure(error || message); | ||
} | ||
} | ||
|
||
function executefetchUserRest() { | ||
try { | ||
const { _id, name, username, emails } = this.user; | ||
const user = { _id, name, username, emails }; | ||
|
||
return API.v1.success({ user }); | ||
} catch ({ error, message }) { | ||
return API.v1.failure(error || message); | ||
} | ||
} | ||
|
||
Api.addRoute(':blogId/:token', { authRequired: true }, { | ||
post: executeAnnouncementRest, | ||
get: executeAnnouncementRest, | ||
}); | ||
|
||
// If a user is editor/admin in Ghost but is not an admin in RC, | ||
// then the e-mail will not be provided to that user | ||
// This method will allow user to fetch user with email. | ||
Api.addRoute(':blogId/:token/getUser', { authRequired: true }, { | ||
post: executefetchUserRest, | ||
get: executefetchUserRest, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import './settings'; | ||
import './methods/admin'; | ||
import './methods/user'; | ||
import './api/api'; | ||
import './lib/triggerHandler'; | ||
import './triggers'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
import { Meteor } from 'meteor/meteor'; | ||
import { HTTP } from 'meteor/http'; | ||
|
||
import { settings } from '../../../settings'; | ||
import { API } from '../utils/url'; | ||
|
||
const api = new API(); | ||
|
||
export const triggerHandler = new class ArticlesSettingsHandler { | ||
constructor() { | ||
this.trigger = {}; | ||
} | ||
|
||
eventNameArgumentsToObject(...args) { | ||
const argObject = { | ||
event: args[0], | ||
}; | ||
switch (argObject.event) { | ||
case 'userEmail': | ||
case 'userRealname': | ||
case 'userAvatar': | ||
case 'userName': | ||
if (args.length >= 2) { | ||
argObject.user = args[1]; | ||
} | ||
break; | ||
case 'roomType': | ||
case 'roomName': | ||
if (args.length >= 2) { | ||
argObject.room = args[1]; | ||
} | ||
break; | ||
case 'siteTitle': | ||
argObject.article = args[1]; | ||
break; | ||
default: | ||
argObject.event = undefined; | ||
break; | ||
} | ||
return argObject; | ||
} | ||
|
||
mapEventArgsToData(data, { event, room, user, article }) { | ||
data.event = event; | ||
switch (event) { | ||
case 'userEmail': | ||
case 'userRealname': | ||
case 'userAvatar': | ||
case 'userName': | ||
data.user_id = user._id; | ||
|
||
if (user.avatar) { | ||
data.avatar = user.avatar; | ||
} | ||
|
||
if (user.name) { | ||
data.name = user.name; | ||
} | ||
|
||
if (user.email) { | ||
data.email = user.email; | ||
} | ||
|
||
if (user.username) { | ||
data.username = user.username; | ||
} | ||
break; | ||
case 'roomType': | ||
case 'roomName': | ||
data.room_id = room.rid; | ||
|
||
if (room.name) { | ||
data.name = room.name; | ||
} | ||
|
||
if (room.type) { | ||
data.type = room.type; | ||
} | ||
break; | ||
case 'siteTitle': | ||
if (article && article.title) { | ||
data.title = article.title; | ||
} | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
|
||
executeTrigger(...args) { | ||
const argObject = this.eventNameArgumentsToObject(...args); | ||
const { event } = argObject; | ||
|
||
if (!event) { | ||
return; | ||
} | ||
|
||
if (settings.get('Articles_enabled')) { | ||
const token = settings.get('Settings_Token'); | ||
this.trigger.api = api.rhooks(token); | ||
this.trigger.retryCount = 5; | ||
} | ||
|
||
this.executeTriggerUrl(argObject, 0); | ||
} | ||
|
||
executeTriggerUrl({ event, room, user, article }, tries = 0) { | ||
if (!this.trigger.api) { | ||
return; | ||
} | ||
const url = this.trigger.api; | ||
|
||
const data = {}; | ||
|
||
this.mapEventArgsToData(data, { event, room, user, article }); | ||
|
||
const opts = { | ||
params: {}, | ||
method: 'POST', | ||
url, | ||
data, | ||
auth: undefined, | ||
npmRequestOptions: { | ||
rejectUnauthorized: !settings.get('Allow_Invalid_SelfSigned_Certs'), | ||
strictSSL: !settings.get('Allow_Invalid_SelfSigned_Certs'), | ||
}, | ||
headers: { | ||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36', | ||
}, | ||
}; | ||
|
||
if (!opts.url || !opts.method) { | ||
return; | ||
} | ||
|
||
HTTP.call(opts.method, opts.url, opts, (error, result) => { | ||
// if the result contained nothing or wasn't a successful statusCode | ||
if (!result) { | ||
if (tries < this.trigger.retryCount) { | ||
// 2 seconds, 4 seconds, 8 seconds | ||
const waitTime = Math.pow(2, tries + 1) * 1000; | ||
|
||
Meteor.setTimeout(() => { | ||
this.executeTriggerUrl({ event, room, user }, tries + 1); | ||
}, waitTime); | ||
} | ||
} | ||
}); | ||
} | ||
}(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { Meteor } from 'meteor/meteor'; | ||
import { HTTP } from 'meteor/http'; | ||
|
||
import { settings } from '../../settings'; | ||
import { API } from './utils/url'; | ||
|
||
const api = new API(); | ||
|
||
export function ghostCleanUp(cookie) { | ||
const rcUrl = Meteor.absoluteUrl().replace(/\/$/, ''); | ||
try { | ||
if (settings.get('Articles_enabled')) { | ||
HTTP.call('DELETE', api.session(), { headers: { cookie, referer: rcUrl } }); | ||
} | ||
} catch (e) { | ||
// Do nothing if failed to logout from Ghost. | ||
// Error will be because user has not logged in to Ghost. | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import { Meteor } from 'meteor/meteor'; | ||
import { HTTP } from 'meteor/http'; | ||
import _ from 'underscore'; | ||
import { Random } from 'meteor/random'; | ||
|
||
import { API } from '../utils/url'; | ||
import { settings } from '../../../settings'; | ||
|
||
const api = new API(); | ||
|
||
// Try to get a verified email, if available. | ||
function getVerifiedEmail(emails) { | ||
const email = _.find(emails, (e) => e.verified); | ||
return email || emails[0].address; | ||
} | ||
|
||
function setupGhost(user, token) { | ||
const rcUrl = Meteor.absoluteUrl().replace(/\/$/, ''); | ||
const blogTitle = settings.get('Article_Site_title'); | ||
const blogToken = Random.id(17); | ||
const announceToken = `${ blogToken }/${ Random.id(24) }`; | ||
const settingsToken = `${ blogToken }/${ Random.id(24) }`; | ||
settings.updateById('Announcement_Token', announceToken); | ||
settings.updateById('Settings_Token', settingsToken); | ||
const data = { | ||
setup: [{ | ||
rc_url: rcUrl, | ||
rc_id: user._id, | ||
rc_token: token, | ||
name: user.name, | ||
email: getVerifiedEmail(user.emails), | ||
announce_token: announceToken, | ||
settings_token: settingsToken, | ||
blogTitle, | ||
}], | ||
}; | ||
return HTTP.call('POST', api.setup(), { data, headers: { 'Content-Type': 'application/json' } }); | ||
} | ||
|
||
function redirectGhost() { | ||
return { | ||
link: api.siteUrl(), | ||
message: 'Ghost is Set up. Redirecting.', | ||
}; | ||
} | ||
|
||
Meteor.methods({ | ||
Articles_admin_panel(token) { | ||
const enabled = settings.get('Articles_enabled'); | ||
|
||
if (!enabled) { | ||
throw new Meteor.Error('Articles are disabled'); | ||
} | ||
const user = Meteor.users.findOne(Meteor.userId()); | ||
|
||
try { | ||
let response = HTTP.call('GET', api.setup()); | ||
|
||
if (response.data && response.data.setup && response.data.setup[0]) { | ||
if (response.data.setup[0].status) { // Ghost site is already setup | ||
return redirectGhost(); | ||
} // Setup Ghost Site and set title | ||
response = setupGhost(user, token); | ||
if (response.statusCode === 201 && response.content) { | ||
return redirectGhost(); | ||
} if (response.errors) { | ||
throw new Meteor.Error(response.errors.message || 'Unable to setup. Make sure Ghost is running'); | ||
} | ||
} else { | ||
throw new Meteor.Error('Unable to redirect. Make sure Ghost is running.'); | ||
} | ||
} catch (e) { | ||
console.log(e); | ||
throw new Meteor.Error(e.error || 'Unable to connect to Ghost. Make sure Ghost is running.'); | ||
} | ||
}, | ||
}); |
Oops, something went wrong.