Skip to content

Commit ca45b30

Browse files
committed
wikis
1 parent 5c604b2 commit ca45b30

File tree

6 files changed

+219
-221
lines changed

6 files changed

+219
-221
lines changed

.env.dev

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
PORT=5000
22
NODE_ENV="development"
33
JWT_SECRET="thisismysupersecrettokenjustkidding"
4-
DATABASE_URL="mongodb://mongo:27017/donut-development"
4+
DATABASE_URL="mongodb://localhost:27017/sugarizerDb"
55
SENDGRID_API_KEY='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'
66
SOCKET_PORT=8810
7-
clientbaseurl = "http://localhost:3000"
7+
clientbaseurl="http://localhost:3000"
88
SOCKET_PORT=8810
99
REDIS_HOST="redis"
1010
REDIS_PORT=6379
1111
REDIS_PASSWORD="auth"
1212
REDIS_DB=0
1313
REDIS_ACTIVITY_DB=1
14+
GITHUB_OAUTH_APP_CLIENTID="a3e08516c35fe7e83f43"
15+
GITHUB_OAUTH_APP_CLIENTSECRET="8393d95c3bfeeb0943045f447a9d055cb660bce0"

app/controllers/wikis.js

Lines changed: 42 additions & 211 deletions
Original file line numberDiff line numberDiff line change
@@ -1,175 +1,23 @@
1+
const axios = require('axios')
12
const HttpStatus = require('http-status-codes')
3+
const WikiHelper = require('../utils/wikis-helper')
24
const HANDLER = require('../utils/response-helper')
3-
const fetch = require('node-fetch')
4-
const base64 = require('base-64')
5-
const axios = require('axios')
5+
const { changeFileOnRemote, addPageToIndex, fetchPagesIndex, updatePagesIndex, getOpts, getOrgId } = WikiHelper
66

7-
const clientId = 'a3e08516c35fe7e83f43'
8-
const clientSecret = '9be3bfa05972a533e1e7843d3e8a69cc0dc3227e'
7+
const clientId = process.env.GITHUB_OAUTH_APP_CLIENTID
8+
const clientSecret = process.env.GITHUB_OAUTH_APP_CLIENTSECRET
99

1010
const githubAPI = 'https://api.github.com'
1111
let accessToken = null
12-
let remoteRepo = null
13-
let adminUserId = null
14-
let orgId = null
15-
16-
const sidebarInitialContent = `
17-
- [$Home$]
18-
- [$Events$]
19-
- [$About$]
20-
- [Google](https://www.google.co.in/)
21-
`
22-
23-
const getUser = async () => {
24-
const opts = { headers: { Authorization: `token ${accessToken}` } }
25-
const respUser = await axios.get(`${githubAPI}/user`, opts)
26-
return (respUser.data.login)
27-
}
28-
29-
const getOrg = async () => {
30-
const opts = { headers: { Authorization: `token ${accessToken}` } }
31-
const respOrg = await axios.get(`${githubAPI}/user/orgs`, opts)
32-
return (respOrg.data[0].login)
33-
}
34-
35-
const getAllRepos = async () => {
36-
const opts = { headers: { Authorization: `token ${accessToken}` } }
37-
const resp = await axios.get(`${githubAPI}/orgs/${orgId}/repos`, opts)
38-
return (resp.data)
39-
}
40-
41-
const fileToIssuesMapping = {} // needs to stored in db
42-
43-
const changeFileOnRemote = async (fileName, content, commitMesage, newFile = false) => {
44-
const opts = { headers: { Authorization: `token ${accessToken}` } }
45-
let resp = null
46-
// base64 the content
47-
let data = {
48-
message: commitMesage,
49-
// committer: {
50-
// name: 'Donut Backend',
51-
// email: 'codeuino@github.com'
52-
// },
53-
content: base64.encode(content)
54-
}
55-
if (!newFile) {
56-
resp = await axios.get(`${githubAPI}/repos/${orgId}/Donut-wikis-backup/contents/${fileName}.md`, opts)
57-
resp = resp.data
58-
console.log(resp.data)
59-
data.sha = resp.sha
60-
}
61-
try {
62-
// create new file on the repo with the provided content
63-
resp = await axios.put(`${githubAPI}/repos/${orgId}/Donut-wikis-backup/contents/${fileName}.md`, data, opts)
64-
// the sha of the commit
65-
const commit = resp.data.commit.sha
66-
console.log(commit)
67-
// open a new issue with the name of the file
68-
if (newFile) {
69-
// open an issue
70-
data = {
71-
title: fileName,
72-
body: 'A demo issue opened by Donut to keep track of commits which change this file'
73-
}
74-
resp = await axios.post(`${githubAPI}/repos/${orgId}/Donut-wikis-backup/issues`, data, opts)
75-
// close the issue
76-
data = {
77-
state: 'closed'
78-
}
79-
fileToIssuesMapping[fileName] = resp.data.number
80-
resp = await axios.patch(`${githubAPI}/repos/${orgId}/Donut-wikis-backup/issues/${resp.data.number}`, data, opts)
81-
}
82-
// comment the sha of the commit on the issue
83-
data = {
84-
body: commit
85-
}
86-
// this is problemactic we cannot do it like this we should get all the issues for search for one which matches this name get its number
87-
resp = await axios.post(`${githubAPI}/repos/${orgId}/Donut-wikis-backup/issues/${fileToIssuesMapping[fileName]}/comments`, data, opts)
88-
} catch (err) {
89-
console.log(err)
90-
}
91-
}
92-
93-
const fetchPage = async (pageName, ref = 'master') => {
94-
const opts = { headers: { Authorization: `token ${accessToken}` } }
95-
const resp = await axios.get(`${githubAPI}/repos/${orgId}/Donut-wikis-backup/contents/${pageName}.md?ref=${ref}`, opts)
96-
return base64.decode(resp.data.content)
97-
}
98-
99-
const getPagesIndex = async () => { // runs on every request, will give an index of all the pages which are there
100-
const opts = { headers: { Authorization: `token ${accessToken}` } }
101-
const toBeReturned = []
102-
toBeReturned.push({ title: '_Sidebar' }) // Sidebar should be at index 0
103-
toBeReturned.push({ title: 'Home' }) // Home with always be at 1 and Home cannot be deleted
104-
toBeReturned[0].content = await fetchPage('_Sidebar') // get the latest sidebar
105-
// toBeReturned[1].content = await fetchPage('Home')
106-
const resp = await axios.get(`${githubAPI}/repos/${orgId}/Donut-wikis-backup/contents`, opts)
107-
resp.data.forEach(ele => {
108-
const eleName = ele.name.substring(0, ele.name.indexOf('.'))
109-
if (eleName !== '_Sidebar' && eleName !== 'Home') {
110-
toBeReturned.push({ title: eleName })
111-
}
112-
})
113-
return toBeReturned
114-
}
115-
116-
const addPageToIndex = async (pagesIndex, page, ref = 'master') => {
117-
for (let i = 0; i < pagesIndex.length; i++) {
118-
if (pagesIndex[i].title === page) {
119-
pagesIndex[i].content = await fetchPage(page, ref)
120-
}
121-
}
122-
return pagesIndex
123-
}
124-
125-
const createRepo = async () => {
126-
const allRepos = await getAllRepos()
127-
const alreadyExists = allRepos.filter(repo => repo.name === 'Donut-wikis-backup')
128-
129-
if (alreadyExists.length) {
130-
console.log('Repository of the name Donut-wikis-backup already exists')
131-
return 'ALREADY_EXISTS'
132-
} else {
133-
const opts = { headers: { Authorization: `token ${accessToken}` } }
134-
const data = {
135-
name: 'Donut-wikis-backup',
136-
private: true,
137-
description: 'Super Private Donut repo'
138-
}
139-
try {
140-
const resp = await axios.post(`${githubAPI}/orgs/${orgId}/repos`, data, opts) // create repo
141-
// create files for initial repo
142-
await changeFileOnRemote('Home', 'This is an awesome Home Page', 'Home Initial Commit', true)
143-
await changeFileOnRemote('_Sidebar', sidebarInitialContent, '_Sidebar Initial Commit', true)
144-
return 'CREATED'
145-
} catch (err) {
146-
console.log(err)
147-
}
148-
}
149-
}
150-
151-
/*
152-
153-
Login and planning
154-
155-
Files could simply not be renamed
156-
fetch the hope page (latest commit) and its histroy and sidebar and send them
157-
we nned another route GET /wikis/:id - this id will contain the page we want and the commit we want
158-
the redis cache will store the data fetched so far so that we dont need to query the github API everytime
159-
for getting content of a page, when the admin updates a page then we clear that item out of the redis cache maybe
160-
161-
*/
16212

16313
module.exports = {
16414

16515
getWikis: async (req, res, next) => {
16616
try {
16717
if (!accessToken) {
168-
res.status(HttpStatus.OK).json({
169-
wikis: 'NO_ACCESS_TOKEN'
170-
})
18+
res.status(HttpStatus.OK).json({ wikis: 'NO_ACCESS_TOKEN' })
17119
} else {
172-
res.status(HttpStatus.OK).json({ wikis: await addPageToIndex(await getPagesIndex(), 'Home') })
20+
res.status(HttpStatus.OK).json({ wikis: await addPageToIndex(await fetchPagesIndex(), 'Home') })
17321
}
17422
} catch (error) {
17523
HANDLER.handleError(res, error)
@@ -178,78 +26,76 @@ module.exports = {
17826

17927
getPage: async (req, res, next) => {
18028
try {
181-
const { title, ref } = req.query
29+
let { title, ref } = req.query
30+
if (!ref) {
31+
ref = 'master'
32+
}
18233
console.log(title)
183-
res.status(HttpStatus.OK).json({ wikis: await addPageToIndex(await getPagesIndex(), title) })
34+
res.status(HttpStatus.OK).json({ wikis: await addPageToIndex(await fetchPagesIndex(), title, ref) })
18435
} catch (err) {
18536
res.status(HttpStatus.BAD_REQUEST).json({ Error: err.message })
18637
}
18738
},
18839

18940
editPage: async (req, res, next) => {
190-
const { title, content } = req.body
191-
console.log('From Edit page')
192-
console.log(title)
193-
console.log(content)
41+
const { title, content, comments } = req.body
19442
try {
195-
await changeFileOnRemote(title, content, `${title} changes`)
43+
await changeFileOnRemote(title, content, `${title} changes - ${comments}`)
19644
if (title !== '_Sidebar') {
197-
res.status(HttpStatus.OK).json({ wikis: await addPageToIndex(await getPagesIndex(), title) })
45+
res.status(HttpStatus.OK).json({ wikis: await addPageToIndex(await fetchPagesIndex(), title) })
19846
} else {
199-
const pagesIndex = await getPagesIndex()
200-
res.status(HttpStatus.OK).json({ wikis: await addPageToIndex(pagesIndex, pagesIndex[1].title) })
47+
await updatePagesIndex()
48+
res.status(HttpStatus.OK).json({ wikis: await addPageToIndex(await fetchPagesIndex(), 'Home') })
20149
}
20250
} catch (err) {
20351
res.status(HttpStatus.BAD_REQUEST).json({ Error: err.message })
20452
}
20553
},
20654

20755
deletePage: async (req, res, next) => {
56+
console.log(getOrgId())
20857
const { title } = req.body
209-
console.log(req.body)
210-
console.log(`!!!!!!!~~~~~~~~~~${title}~~~~~~~~~~~!!!!!!!!!!!`)
211-
const opts = { headers: { Authorization: `token ${accessToken}` } }
21258
try {
213-
let resp = await axios.get(`${githubAPI}/repos/${orgId}/Donut-wikis-backup/contents/${title}.md`, opts)
214-
resp = resp.data
215-
console.log(resp.sha)
21659
const data = {
21760
message: `${title} deleted`,
218-
sha: resp.sha
61+
sha: (await axios.get(`${githubAPI}/repos/${getOrgId()}/Donut-wikis-backup/contents/${title}.md`, getOpts())).data.sha
21962
}
220-
resp = await axios.delete(`${githubAPI}/repos/${orgId}/Donut-wikis-backup/contents/${title}.md`, {
63+
const deleteCommit = (await axios.delete(`${githubAPI}/repos/${getOrgId()}/Donut-wikis-backup/contents/${title}.md`, {
22164
data: data,
222-
headers: opts.headers
223-
})
224-
// console.log(resp)
225-
const pagesIndex = await getPagesIndex()
226-
res.status(HttpStatus.OK).json({ wikis: await addPageToIndex(pagesIndex, pagesIndex[1].title) })
65+
headers: getOpts().headers
66+
})).data.commit.sha
67+
const issueNumber = await WikiHelper.getFileIssueNumber(title)
68+
await axios.post(`${githubAPI}/repos/${getOrgId()}/Donut-wikis-backup/issues/${issueNumber}/comments`, { body: deleteCommit }, getOpts())
69+
await axios.patch(`${githubAPI}/repos/${getOrgId()}/Donut-wikis-backup/issues/${issueNumber}`, { title: `${title}-deleted-${deleteCommit.substring(0, 8)}` }, getOpts())
70+
await updatePagesIndex()
71+
await WikiHelper.clearPageFromCache(title)
72+
res.status(HttpStatus.OK).json({ wikis: await addPageToIndex(await fetchPagesIndex(), 'Home') })
22773
} catch (err) {
22874
res.status(HttpStatus.BAD_REQUEST).json({ Error: err.message })
22975
}
23076
},
23177

23278
newPage: async (req, res, next) => {
233-
const { title, content } = req.body
79+
const { title, content, comments } = req.body
23480
try {
235-
await changeFileOnRemote(title, content, `${title} initial commit`, true)
236-
res.status(HttpStatus.OK).json({ wikis: await addPageToIndex(await getPagesIndex(), title) })
81+
await changeFileOnRemote(title, content, `${title} initial commit - ${comments}`, true)
82+
await updatePagesIndex()
83+
res.status(HttpStatus.OK).json({ wikis: await addPageToIndex(await fetchPagesIndex(), title) })
23784
} catch (err) {
23885
res.status(HttpStatus.BAD_REQUEST).json({ Error: err.message })
23986
}
24087
},
24188

242-
// http://thecodebarbarian.com/github-oauth-login-with-node-js.html
243-
24489
oauthCheck: async (req, res, next) => {
24590
console.log(accessToken)
24691
if (!accessToken) {
24792
console.log('redirected to github auth')
248-
res.redirect(
249-
`https://github.com/login/oauth/authorize?client_id=${clientId}&scope=repo`
250-
)
93+
res.status(HttpStatus.OK).json({
94+
redirect: true,
95+
redirect_url: `https://github.com/login/oauth/authorize?client_id=${clientId}&scope=repo`
96+
})
25197
} else {
252-
res.redirect(`${process.env.clientbaseurl}wikis`)
98+
res.redirect(`${process.env.clientbaseurl}/wikis`)
25399
}
254100
},
255101

@@ -262,29 +108,14 @@ module.exports = {
262108
const opts = { headers: { accept: 'application/json' } }
263109
try {
264110
const resp = await axios.post('https://github.com/login/oauth/access_token', body, opts)
265-
console.log('From OAuth Callback')
266-
console.log(resp.data)
267111
accessToken = resp.data.access_token
268-
adminUserId = await getUser()
269-
orgId = await getOrg()
270-
console.log(`accessToken = ${accessToken}`)
271-
console.log(`orgId = ${orgId}`)
272-
await createRepo()
273-
res.redirect(`${process.env.clientbaseurl}wikis`)
112+
WikiHelper.setOpts(accessToken)
113+
await WikiHelper.getOrg()
114+
await WikiHelper.createRepo()
115+
await updatePagesIndex()
116+
res.redirect(`${process.env.clientbaseurl}/wikis`)
274117
} catch (err) {
275118
res.status(500).json({ message: err.message })
276119
}
277120
}
278121
}
279-
280-
/* Stuff yet to do
281-
That comments part in the ediotr in the front end should be in the commit message
282-
Should give some kind of feedback to the user when we have to make him wait, like a spinner or something
283-
Implement chaching to make things work faster
284-
Disable title editing everywhere
285-
implement histories in backed and frontend both
286-
discuss with jaskirat about the desgin aspects which siddhart recomended
287-
288-
Fixed
289-
implement deleting of pages
290-
*/

app/routes/wikis.js

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
const express = require('express')
22
const router = express.Router()
3+
const auth = require('../middleware/auth')
34
const wikisController = require('../controllers/wikis')
5+
const isUnderMaintenance = require('../middleware/maintenance')
46

5-
router.get('/', wikisController.getWikis)
6-
// router.put('/', wikisController.editWikis)
7-
router.get('/oauth-callback', wikisController.oauthCallback)
8-
router.get('/oauth-check', wikisController.oauthCheck)
9-
router.get('/pages', wikisController.getPage)
10-
router.post('/pages', wikisController.newPage)
11-
router.put('/pages', wikisController.editPage)
12-
router.delete('/pages', wikisController.deletePage)
7+
router.get('/', isUnderMaintenance, auth, wikisController.getWikis)
8+
router.get('/oauth-callback', isUnderMaintenance, wikisController.oauthCallback)
9+
router.get('/oauth-check', isUnderMaintenance, auth, wikisController.oauthCheck)
10+
router.get('/pages', isUnderMaintenance, auth, wikisController.getPage)
11+
router.post('/pages', isUnderMaintenance, auth, wikisController.newPage)
12+
router.put('/pages', isUnderMaintenance, auth, wikisController.editPage)
13+
router.delete('/pages', isUnderMaintenance, auth, wikisController.deletePage)
1314
module.exports = router

0 commit comments

Comments
 (0)