From 079822dfecfba659a491034c447c679dab2424c7 Mon Sep 17 00:00:00 2001 From: Jason Croft Date: Mon, 9 May 2016 16:27:35 -0400 Subject: [PATCH 01/21] Start extending to support GitLab authentication. Add necessary dependency. Add baseURL parameter for self-hosted GitLab Add necessary require. Add block for GitLab auth. Fix typo Update font-awesome dependency for GitLab icon. Use a color closer to GitLab orange. More direct TODO --- app.js | 17 +++++++++++++++++ bower.json | 2 +- config.json | 5 +++++ lib/auth.js | 10 ++++++++++ lib/config.js | 2 ++ lib/response.js | 2 ++ package.json | 1 + public/views/modal.ejs | 5 +++++ 8 files changed, 43 insertions(+), 1 deletion(-) diff --git a/app.js b/app.js index c3c824a6..a6eded98 100644 --- a/app.js +++ b/app.js @@ -292,6 +292,23 @@ if (config.github) { //github callback actions app.get('/auth/github/callback/:noteId/:action', response.githubActions); } +//gitlab auth +if (config.gitlab) { + app.get('/auth/gitlab', + passport.authenticate('gitlab'), + function (req, res) {}); + //gitlab auth callback + app.get('/auth/gitlab/callback', + passport.authenticate('gitlab', { + failureRedirect: config.serverurl + }), + function (req, res) { + res.redirect(config.serverurl); + }); + //gitlab callback actions + // TODO: Maybe in the future + //app.get('/auth/gitlab/callback/:noteId/:action', response.gitlabActions); +} //dropbox auth if (config.dropbox) { app.get('/auth/dropbox', diff --git a/bower.json b/bower.json index fcc73317..70973750 100644 --- a/bower.json +++ b/bower.json @@ -20,7 +20,7 @@ "dependencies": { "bootstrap": "~3.3.6", "jquery": "~1.11.3", - "font-awesome": "~4.5.0", + "font-awesome": "~4.6.0", "Ionicons": "ionicons#~2.0.1", "reveal.js": "~3.2.0", "gsap": "greensock#~1.18.0", diff --git a/config.json b/config.json index 16ad258b..c65e9c7c 100644 --- a/config.json +++ b/config.json @@ -32,6 +32,11 @@ "clientID": "change this", "clientSecret": "change this" }, + "gitlab": { + "baseURL": "change this", + "clientID": "change this", + "clientSecret": "change this" + }, "dropbox": { "clientID": "change this", "clientSecret": "change this" diff --git a/lib/auth.js b/lib/auth.js index af3e8d1d..d495605a 100644 --- a/lib/auth.js +++ b/lib/auth.js @@ -4,6 +4,7 @@ var passport = require('passport'); var FacebookStrategy = require('passport-facebook').Strategy; var TwitterStrategy = require('passport-twitter').Strategy; var GithubStrategy = require('passport-github').Strategy; +var GitlabStrategy = require('passport-gitlab2').Strategy; var DropboxStrategy = require('passport-dropbox-oauth2').Strategy; //core @@ -56,6 +57,15 @@ if (config.github) { callbackURL: config.serverurl + '/auth/github/callback' }, callback)); } +//gitlab +if (config.gitlab) { + passport.use(new GitlabStrategy({ + baseURL: config.gitlab.baseURL, + clientID: config.gitlab.clientID, + clientSecret: config.gitlab.clientSecret, + callbackURL: config.serverurl + '/auth/gitlab/callback' + }, callback)); +} //dropbox if (config.dropbox) { passport.use(new DropboxStrategy({ diff --git a/lib/config.js b/lib/config.js index 6738d4a8..c138b459 100644 --- a/lib/config.js +++ b/lib/config.js @@ -59,6 +59,7 @@ var documentmaxlength = config.documentmaxlength || 100000; var facebook = config.facebook || false; var twitter = config.twitter || false; var github = config.github || false; +var gitlab = config.gitlab || false; var dropbox = config.dropbox || false; var imgur = config.imgur || false; @@ -110,6 +111,7 @@ module.exports = { facebook: facebook, twitter: twitter, github: github, + gitlab: gitlab, dropbox: dropbox, imgur: imgur }; \ No newline at end of file diff --git a/lib/response.js b/lib/response.js index 7a75e234..2114c99b 100644 --- a/lib/response.js +++ b/lib/response.js @@ -94,6 +94,7 @@ function showIndex(req, res, next) { facebook: config.facebook, twitter: config.twitter, github: config.github, + gitlab: config.gitlab, dropbox: config.dropbox, }); res.write(content); @@ -124,6 +125,7 @@ function responseHackMD(res, note) { facebook: config.facebook, twitter: config.twitter, github: config.github, + gitlab: config.gitlab, dropbox: config.dropbox, }); var buf = html; diff --git a/package.json b/package.json index a70bce31..3ecaa842 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "passport-dropbox-oauth2": "^1.0.0", "passport-facebook": "^2.1.0", "passport-github": "^1.1.0", + "passport-gitlab2": "^2.2.0", "passport-twitter": "^1.0.4", "passport.socketio": "^3.6.1", "pg": "^4.5.3", diff --git a/public/views/modal.ejs b/public/views/modal.ejs index 260ff423..4eb33bf3 100644 --- a/public/views/modal.ejs +++ b/public/views/modal.ejs @@ -28,6 +28,11 @@ Sign in via Dropbox <% } %> + <% if(gitlab) { %> + + Sign in via GitLab + + <% } %> From 277bf60a2ea539645428360734f9f8d2e33e3631 Mon Sep 17 00:00:00 2001 From: Jason Croft Date: Mon, 9 May 2016 17:06:44 -0400 Subject: [PATCH 02/21] Add GitLab options. --- public/views/header.ejs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/public/views/header.ejs b/public/views/header.ejs index 40dee0b0..18369ba9 100644 --- a/public/views/header.ejs +++ b/public/views/header.ejs @@ -42,6 +42,10 @@
  • Gist
  • <% } %> + <% if(typeof gitlab !== 'undefined' && gitlab) { %> +
  • Snippet +
  • + <% } %>
  • Dropbox @@ -50,6 +54,8 @@
  • Gist
  • +
  • Snippet +
  • Clipboard
  • @@ -127,6 +133,10 @@
  • Gist
  • <% } %> + <% if(typeof gitlab !== 'undefined' && gitlab) { %> +
  • Snippet +
  • + <% } %>
  • Dropbox @@ -135,6 +145,8 @@
  • Gist
  • +
  • Snippet +
  • Clipboard
  • From 476cabd10952f026f331754baf9846b1aad917cd Mon Sep 17 00:00:00 2001 From: Jason Croft Date: Mon, 9 May 2016 17:07:02 -0400 Subject: [PATCH 03/21] Attach to snippet classes. --- public/js/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/public/js/index.js b/public/js/index.js index 3f0ed593..0b10c9e0 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -496,12 +496,14 @@ var ui = { export: { dropbox: $(".ui-save-dropbox"), googleDrive: $(".ui-save-google-drive"), - gist: $(".ui-save-gist") + gist: $(".ui-save-gist"), + snippet: $(".ui-save-snippet") }, import: { dropbox: $(".ui-import-dropbox"), googleDrive: $(".ui-import-google-drive"), gist: $(".ui-import-gist"), + snippet: $(".ui-import-snippet"), clipboard: $(".ui-import-clipboard") }, beta: { From 521f96fb11af9b2669c6d7002f983d3e7cc99e79 Mon Sep 17 00:00:00 2001 From: Jason Croft Date: Mon, 9 May 2016 17:07:23 -0400 Subject: [PATCH 04/21] Skeletons for GitLab actions. --- lib/response.js | 83 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/lib/response.js b/lib/response.js index 2114c99b..63099b8d 100644 --- a/lib/response.js +++ b/lib/response.js @@ -321,6 +321,17 @@ function actionGist(req, res, note) { res.redirect("https://github.com/login/oauth/authorize?" + query); } +function actionSnippet(req, res, note) { + var data = { + client_id: config.gitlab.clientID, + redirect_uri: config.serverurl + '/auth/github/callback/' + LZString.compressToBase64(note.id) + '/gist', + scope: "snippet", + state: shortId.generate() + }; + var query = querystring.stringify(data); + res.redirect(config.gitlab.baseURL + "/login/oauth/authorize?" + query); +} + function noteActions(req, res, next) { var noteId = req.params.noteId; findNote(req, res, function (note) { @@ -378,6 +389,21 @@ function githubActions(req, res, next) { }); } +function gitlabActions(req, res, next) { + var noteId = req.params.noteId; + findNote(req, res, function (note) { + var action = req.params.action; + switch (action) { + case "gist": + gitlabActionSnippet(req, res, note); + break; + default: + res.redirect(config.serverurl + '/' + noteId); + break; + } + }); +} + function githubActionGist(req, res, note) { var code = req.query.code; var state = req.query.state; @@ -435,6 +461,63 @@ function githubActionGist(req, res, note) { } } +function gitlabActionSnippet(req, res, note) { + var code = req.query.code; + var state = req.query.state; + if (!code || !state) { + return response.errorForbidden(res); + } else { + var data = { + client_id: config.gitlab.clientID, + client_secret: config.gitlab.clientSecret, + code: code, + state: state + } + var auth_url = config.gitlab.baseURL + '/login/oauth/access_token'; + request({ + url: auth_url, + method: "POST", + json: data + }, function (error, httpResponse, body) { + if (!error && httpResponse.statusCode == 200) { + var access_token = body.access_token; + if (access_token) { + var content = LZString.decompressFromBase64(note.content); + var title = models.Note.decodeTitle(note.title); + var filename = title.replace('/', ' ') + '.md'; + var gist = { + "files": {} + }; + gist.files[filename] = { + "content": content + }; + var gist_url = "https://api.gitlab.com/snippets"; + request({ + url: gist_url, + headers: { + 'User-Agent': 'HackMD', + 'Authorization': 'token ' + access_token + }, + method: "POST", + json: gist + }, function (error, httpResponse, body) { + if (!error && httpResponse.statusCode == 201) { + res.setHeader('referer', ''); + res.redirect(body.html_url); + } else { + return response.errorForbidden(res); + } + }); + } else { + return response.errorForbidden(res); + } + } else { + return response.errorForbidden(res); + } + }) + } +} + function showPublishSlide(req, res, next) { findNote(req, res, function (note) { note.increment('viewcount').then(function (note) { From 17d2249ec31bce28f79e8def4be1515ac465d29b Mon Sep 17 00:00:00 2001 From: Jason Croft Date: Mon, 9 May 2016 22:37:51 -0400 Subject: [PATCH 05/21] Define snippet import modal --- public/views/body.ejs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/public/views/body.ejs b/public/views/body.ejs index 771da880..23a3acef 100644 --- a/public/views/body.ejs +++ b/public/views/body.ejs @@ -151,4 +151,24 @@ + + <%- include modal %> \ No newline at end of file From 70f6e5bc2cbdb15ff48bdf49b09d7c4bb78ea4ba Mon Sep 17 00:00:00 2001 From: Jason Croft Date: Mon, 9 May 2016 22:38:13 -0400 Subject: [PATCH 06/21] Define events for snippet actions --- public/js/index.js | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/public/js/index.js b/public/js/index.js index 0b10c9e0..17516169 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -1136,6 +1136,8 @@ ui.toolbar.export.googleDrive.click(function (e) { }); //export to gist ui.toolbar.export.gist.attr("href", noteurl + "/gist"); +//export to snippet +ui.toolbar.export.snippet.attr("href", noteurl + "/snippet"); //import from dropbox ui.toolbar.import.dropbox.click(function () { var options = { @@ -1188,6 +1190,10 @@ function buildImportFromGoogleDrive() { ui.toolbar.import.gist.click(function () { //na }); +//import from snippet +ui.toolbar.import.snippet.click(function () { + //na +}); //import from clipboard ui.toolbar.import.clipboard.click(function () { //na @@ -1355,6 +1361,45 @@ $("#gistImportModalConfirm").click(function () { } }); +// snippet import modal +$("#snippetImportModalClear").click(function () { + $("#snippetImportModalContent").val(''); +}); +$("#snippetImportModalConfirm").click(function () { + var snippeturl = $("#snippetImportModalContent").val(); + if (!snippeturl) return; + $('#snippetImportModal').modal('hide'); + $("#snippetImportModalContent").val(''); + if (!isValidURL(snippeturl)) { + showMessageModal(' Import from Snippet', 'Not a valid URL :(', '', '', false); + return; + } else { + // TODO: Validate against config.gitlab.baseURL + ui.spinner.show(); + $.get(snippeturl) + .success(function (data) { + if (data.files) { + var contents = ""; + Object.keys(data.files).forEach(function (key) { + contents += key; + contents += '\n---\n'; + contents += data.files[key].content; + contents += '\n\n'; + }); + replaceAll(contents); + } else { + showMessageModal(' Import from Snippet', 'Unable to fetch snippet files :(', '', '', false); + } + }) + .error(function (data) { + showMessageModal(' Import from Snippet', 'Not a valid Snippet URL :(', '', JSON.stringify(data), false); + }) + .complete(function () { + ui.spinner.hide(); + }); + } +}); + function parseToEditor(data) { var parsed = toMarkdown(data); if (parsed) From a443490ee6257d2e2a5dfabcd9455101c1a5b4c0 Mon Sep 17 00:00:00 2001 From: Jason Croft Date: Wed, 11 May 2016 17:04:45 -0400 Subject: [PATCH 07/21] Add accessToken column --- lib/models/user.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/models/user.js b/lib/models/user.js index e1a373d6..639fc226 100644 --- a/lib/models/user.js +++ b/lib/models/user.js @@ -23,6 +23,9 @@ module.exports = function (sequelize, DataTypes) { }, history: { type: DataTypes.TEXT + }, + accessToken: { + type: DataTypes.STRING } }, { classMethods: { @@ -72,6 +75,6 @@ module.exports = function (sequelize, DataTypes) { } } }); - + return User; }; \ No newline at end of file From 17daf322398c804fa91c08c16c3f48ada4d17b95 Mon Sep 17 00:00:00 2001 From: Jason Croft Date: Wed, 11 May 2016 17:04:55 -0400 Subject: [PATCH 08/21] Remove skeleton functions --- lib/response.js | 83 ------------------------------------------------- 1 file changed, 83 deletions(-) diff --git a/lib/response.js b/lib/response.js index 63099b8d..2114c99b 100644 --- a/lib/response.js +++ b/lib/response.js @@ -321,17 +321,6 @@ function actionGist(req, res, note) { res.redirect("https://github.com/login/oauth/authorize?" + query); } -function actionSnippet(req, res, note) { - var data = { - client_id: config.gitlab.clientID, - redirect_uri: config.serverurl + '/auth/github/callback/' + LZString.compressToBase64(note.id) + '/gist', - scope: "snippet", - state: shortId.generate() - }; - var query = querystring.stringify(data); - res.redirect(config.gitlab.baseURL + "/login/oauth/authorize?" + query); -} - function noteActions(req, res, next) { var noteId = req.params.noteId; findNote(req, res, function (note) { @@ -389,21 +378,6 @@ function githubActions(req, res, next) { }); } -function gitlabActions(req, res, next) { - var noteId = req.params.noteId; - findNote(req, res, function (note) { - var action = req.params.action; - switch (action) { - case "gist": - gitlabActionSnippet(req, res, note); - break; - default: - res.redirect(config.serverurl + '/' + noteId); - break; - } - }); -} - function githubActionGist(req, res, note) { var code = req.query.code; var state = req.query.state; @@ -461,63 +435,6 @@ function githubActionGist(req, res, note) { } } -function gitlabActionSnippet(req, res, note) { - var code = req.query.code; - var state = req.query.state; - if (!code || !state) { - return response.errorForbidden(res); - } else { - var data = { - client_id: config.gitlab.clientID, - client_secret: config.gitlab.clientSecret, - code: code, - state: state - } - var auth_url = config.gitlab.baseURL + '/login/oauth/access_token'; - request({ - url: auth_url, - method: "POST", - json: data - }, function (error, httpResponse, body) { - if (!error && httpResponse.statusCode == 200) { - var access_token = body.access_token; - if (access_token) { - var content = LZString.decompressFromBase64(note.content); - var title = models.Note.decodeTitle(note.title); - var filename = title.replace('/', ' ') + '.md'; - var gist = { - "files": {} - }; - gist.files[filename] = { - "content": content - }; - var gist_url = "https://api.gitlab.com/snippets"; - request({ - url: gist_url, - headers: { - 'User-Agent': 'HackMD', - 'Authorization': 'token ' + access_token - }, - method: "POST", - json: gist - }, function (error, httpResponse, body) { - if (!error && httpResponse.statusCode == 201) { - res.setHeader('referer', ''); - res.redirect(body.html_url); - } else { - return response.errorForbidden(res); - } - }); - } else { - return response.errorForbidden(res); - } - } else { - return response.errorForbidden(res); - } - }) - } -} - function showPublishSlide(req, res, next) { findNote(req, res, function (note) { note.increment('viewcount').then(function (note) { From 3dd3e6bc3596c0bba50dca3d1789f55883e0f681 Mon Sep 17 00:00:00 2001 From: Jason Croft Date: Wed, 11 May 2016 17:05:25 -0400 Subject: [PATCH 09/21] Allow importing from GitLab snippet --- public/js/index.js | 69 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 21 deletions(-) diff --git a/public/js/index.js b/public/js/index.js index 17516169..7b22f7fa 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -243,6 +243,15 @@ var lastInfo = { }; var personalInfo = {}; var onlineUsers = []; +var fileTypes = { + "pl": "perl", + "cgi": "perl", + "js": "javascript", + "php": "php", + "sh": "bash", + "rb": "ruby", + "html": "html" +} //editor settings var textit = document.getElementById("textit"); @@ -1192,7 +1201,22 @@ ui.toolbar.import.gist.click(function () { }); //import from snippet ui.toolbar.import.snippet.click(function () { - //na + $.get(serverurl + '/gitlab') + .success(function (data) { + $("#snippetImportModalAccessToken").val(data.accesstoken); + $("#snippetImportModalBaseURL").val(data.baseURL); + $("#snippetImportModalContent").prop('disabled', false); + $("#snippetImportModalConfirm").prop('disabled', false); + $("#snippetImportModalLoading").hide(); + $("#snippetImportModal").modal('toggle'); + }) + .error(function (data) { + showMessageModal(' Import from Snippet', 'Unable to fetch gitlab parameters :(', '', '', false); + }) + .complete(function () { + //na + }); + return false; }); //import from clipboard ui.toolbar.import.clipboard.click(function () { @@ -1370,32 +1394,35 @@ $("#snippetImportModalConfirm").click(function () { if (!snippeturl) return; $('#snippetImportModal').modal('hide'); $("#snippetImportModalContent").val(''); - if (!isValidURL(snippeturl)) { - showMessageModal(' Import from Snippet', 'Not a valid URL :(', '', '', false); - return; + if (!/^.+\/snippets\/.+$/.test(snippeturl)) { + showMessageModal(' Import from Snippet', 'Not a valid Snippet URL :(', '', '', false); } else { - // TODO: Validate against config.gitlab.baseURL ui.spinner.show(); - $.get(snippeturl) - .success(function (data) { - if (data.files) { - var contents = ""; - Object.keys(data.files).forEach(function (key) { - contents += key; - contents += '\n---\n'; - contents += data.files[key].content; - contents += '\n\n'; + var accessToken = '?access_token=' + $("#snippetImportModalAccessToken").val(); + var fullURL = $("#snippetImportModalBaseURL").val() + '/api/v3' + snippeturl; + $.get(fullURL + accessToken) + .success(function(data) { + var content = '# ' + (data.title || "Snippet Import"); + var fileInfo = data.file_name.split('.'); + $.get(fullURL + '/raw' + accessToken) + .success(function (raw) { + if (raw) { + content += "\n\n```"; + content += fileTypes[fileInfo[1]] + "=\n"; + content += raw; + content += "\n```"; + replaceAll(content); + } + }) + .error(function (data) { + showMessageModal(' Import from Snippet', 'Not a valid Snippet URL :(', '', JSON.stringify(data), false); + }) + .complete(function () { + ui.spinner.hide(); }); - replaceAll(contents); - } else { - showMessageModal(' Import from Snippet', 'Unable to fetch snippet files :(', '', '', false); - } }) .error(function (data) { showMessageModal(' Import from Snippet', 'Not a valid Snippet URL :(', '', JSON.stringify(data), false); - }) - .complete(function () { - ui.spinner.hide(); }); } }); From 9f401b3fa88aa60c435c548f807fbb0742aaa2e0 Mon Sep 17 00:00:00 2001 From: Jason Croft Date: Wed, 11 May 2016 17:05:53 -0400 Subject: [PATCH 10/21] Fully-fleshed snippetImportModal --- public/views/body.ejs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/public/views/body.ejs b/public/views/body.ejs index 23a3acef..039690ef 100644 --- a/public/views/body.ejs +++ b/public/views/body.ejs @@ -158,15 +158,17 @@ From e545de72a6daab8f51d4b39ec9e33563eb16ee68 Mon Sep 17 00:00:00 2001 From: Jason Croft Date: Wed, 11 May 2016 17:06:05 -0400 Subject: [PATCH 11/21] Add accessToken saving. --- lib/auth.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/auth.js b/lib/auth.js index d495605a..ec45eea3 100644 --- a/lib/auth.js +++ b/lib/auth.js @@ -19,13 +19,23 @@ function callback(accessToken, refreshToken, profile, done) { profileid: profile.id.toString() }, defaults: { - profile: JSON.stringify(profile) + profile: JSON.stringify(profile), + accessToken: accessToken, + refreshToken: refreshToken } }).spread(function(user, created) { if (user) { - if (config.debug) - logger.info('user login: ' + user.id); - return done(null, user); + if(user.accessToken == accessToken){ + if (config.debug) + logger.info('user login: ' + user.id); + return done(null, user); + } + user.accessToken = accessToken; + user.save().then(function(){ + if (config.debug) + logger.info('user login: ' + user.id); + return done(null, user); + }) } }).catch(function(err) { logger.error('auth callback failed: ' + err); From ad79b581bda79ef2be0d6ad1a192fc7d0afef2f0 Mon Sep 17 00:00:00 2001 From: Jason Croft Date: Wed, 11 May 2016 17:06:18 -0400 Subject: [PATCH 12/21] End-point to get GitLab data. --- app.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/app.js b/app.js index a6eded98..964a3a81 100644 --- a/app.js +++ b/app.js @@ -16,6 +16,7 @@ var formidable = require('formidable'); var morgan = require('morgan'); var passportSocketIo = require("passport.socketio"); var helmet = require('helmet'); +var request = require('request'); //core var config = require("./lib/config.js"); @@ -82,6 +83,9 @@ var sessionStore = new SequelizeStore({ //compression app.use(compression()); +//cookies +app.use(cookieParser()); + // use hsts to tell https users stick to this app.use(helmet.hsts({ maxAge: 31536000 * 1000, // 365 days @@ -438,6 +442,18 @@ app.post('/uploadimage', function (req, res) { } }); }); +//get gitlab parameters +app.get('/gitlab', function (req, res) { + var ret = { baseURL: config.gitlab.baseURL }; + models.User.findById(req.cookies.userid) + .then(function(user) { + ret.accesstoken = user.accessToken; + return res.send(ret); + }).catch(function(err) { + logger.error('user search failed: ' + err); + return done(err, null); + }); +}); //get new note app.get("/new", response.newNote); //get publish note From de998c4a0fcbadc4c0353c8e65d5769c271cfcd9 Mon Sep 17 00:00:00 2001 From: Jason Croft Date: Wed, 11 May 2016 21:12:48 -0400 Subject: [PATCH 13/21] Check to make sure GitLab is configured before showing import option. --- public/views/header.ejs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/views/header.ejs b/public/views/header.ejs index 18369ba9..051817dc 100644 --- a/public/views/header.ejs +++ b/public/views/header.ejs @@ -54,8 +54,10 @@
  • Gist
  • + <% if(typeof gitlab !== 'undefined' && gitlab) { %>
  • Snippet
  • + <% } %>
  • Clipboard
  • @@ -145,8 +147,10 @@
  • Gist
  • + <% if(typeof gitlab !== 'undefined' && gitlab) { %>
  • Snippet
  • + <% } %>
  • Clipboard
  • From c16345ab128288b92023e789f09cabb5197d1181 Mon Sep 17 00:00:00 2001 From: Jason Croft Date: Thu, 12 May 2016 11:19:14 -0400 Subject: [PATCH 14/21] Can now select from available projects and snippets to build import URL. --- app.js | 14 ++++++++++-- public/css/index.css | 5 +++++ public/js/index.js | 51 +++++++++++++++++++++++++++++++++++++++++++ public/views/body.ejs | 20 +++++++++++++++-- 4 files changed, 86 insertions(+), 4 deletions(-) diff --git a/app.js b/app.js index 964a3a81..60eb61b5 100644 --- a/app.js +++ b/app.js @@ -448,10 +448,20 @@ app.get('/gitlab', function (req, res) { models.User.findById(req.cookies.userid) .then(function(user) { ret.accesstoken = user.accessToken; - return res.send(ret); + request( + config.gitlab.baseURL + '/api/v3/projects?access_token=' + user.accessToken, + function(error, httpResponse, body) { + if (!error && httpResponse.statusCode == 200) { + ret.projects = JSON.parse(body); + return res.send(ret); + } else { + return res.send(ret); + } + } + ); }).catch(function(err) { logger.error('user search failed: ' + err); - return done(err, null); + return response.errorInternalError(res); }); }); //get new note diff --git a/public/css/index.css b/public/css/index.css index fdfae0ac..aaf84a04 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -328,6 +328,11 @@ div[contenteditable]:empty:not(:focus):before{ border-bottom: 1px solid #ccc; } +.snippet-import-or { + text-align: center; + width: 100%; +} + .status-bar { background: #1c1c1e; border-top: 1px solid #343434; diff --git a/public/js/index.js b/public/js/index.js index 7b22f7fa..199c678e 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -552,6 +552,10 @@ var ui = { codemirrorSizer: $(".ui-edit-area .CodeMirror .CodeMirror-sizer"), codemirrorSizerInner: $(".ui-edit-area .CodeMirror .CodeMirror-sizer > div"), markdown: $(".ui-view-area .markdown-body") + }, + modal: { + snippetProjects: $("#snippetImportModalProjects"), + snippetSnippets: $("#snippetImportModalSnippets") } }; @@ -1209,6 +1213,17 @@ ui.toolbar.import.snippet.click(function () { $("#snippetImportModalConfirm").prop('disabled', false); $("#snippetImportModalLoading").hide(); $("#snippetImportModal").modal('toggle'); + $("#snippetImportModalProjects").find('option').remove().end().append(''); + if (data.projects) { + data.projects.sort(function(a,b) { + return (a.path_with_namespace < b.path_with_namespace) ? -1 : ((a.path_with_namespace > b.path_with_namespace) ? 1 : 0); + }); + data.projects.forEach(function(project) { + $(''); + data.forEach(function(snippet) { + $('