add link sharing

master
Garrett Mills 3 years ago
parent 2b95fc17a6
commit dc2cec78dc
  1. 3
      app/MiscUnit.js
  2. 18
      app/assets/dash_v1.css
  3. 48
      app/controllers/api/v1.controller.js
  4. 46
      app/controllers/dash/v1.controller.js
  5. 13
      app/models/v1/Invite.model.js
  6. 6
      app/routing/Middleware.js
  7. 26
      app/routing/middleware/v1/Invite.middleware.js
  8. 2
      app/routing/routers/api/v1.routes.js
  9. 6
      app/routing/routers/dash/v1.routes.js
  10. 19
      app/views/dash_v1/accept.pug
  11. 7
      app/views/dash_v1/invite.pug
  12. 3
      app/views/dash_v1/share.pug
  13. 3
      config/server.config.js
  14. 3
      example.env

@ -37,7 +37,8 @@ class MiscUnit extends Unit {
global.devbug = {
version: '0.2.0',
code: {
node: `dbsetup({
node: `require("devbugjs")
dbsetup({
\tserver: "https://CHANGEME:8000/", // DevBug Server URL
\tproject: "CHANGEME", // Project API Key
})`,

@ -87,6 +87,24 @@ a {
color: #eee;
}
.btn {
margin: 5;
margin-bottom: 20;
padding: 5;
padding-left: 10;
padding-right: 10;
background: #509d9d;
border-radius: 7px;
text-decoration: none;
color: white;
transition: all 0.5s ease;
}
.btn:hover {
background: #eee;
color: #307d7d;
}
pre {outline: 1px solid #ccc; padding: 5px; margin: 5px; }
.string { color: darkslateblue; }
.number { color: darkorange; }

@ -5,6 +5,7 @@
*/
const Out = _flitter.model('v1:Out')
const Project = _flitter.model('v1:Project')
const Invite = _flitter.model('v1:Invite')
class v1 {
/*
@ -66,6 +67,53 @@ class v1 {
success: true
})
}
async invite_show(req, res, next){
const invite = await Invite.findById(req.params.id)
if ( !invite ) _flitter.error(res, 404, {reason: 'Invitation not found with the specified URL.'})
if ( invite.used ) _flitter.error(res, 401, {reason: 'This invitation link has been used or has expired.'})
const project = await Project.findById(invite.project_id)
if ( !project ) _flitter.error(res, 404, {reason: 'This project no longer exists.'})
const user = await _flitter.model('User').findOne({uuid: invite.by_user_id})
if ( !user ) _flitter.error(res, 500, {reason: 'This user no longer exists. Sorry.'})
return _flitter.view(res, 'dash_v1:accept', {invite, project, user})
}
async invite_accept(req, res, next){
const invite = await Invite.findById(req.params.id)
if ( !invite ) _flitter.error(res, 404, {reason: 'Invitation not found with the specified URL.'})
if ( invite.used ) _flitter.error(res, 401, {reason: 'This invitation link has been used or has expired.'})
const project = await Project.findById(invite.project_id)
if ( !project ) _flitter.error(res, 404, {reason: 'This project no longer exists.'})
const user = await _flitter.model('User').findOne({uuid: invite.by_user_id})
if ( !user ) _flitter.error(res, 500, {reason: 'This user no longer exists. Sorry.'})
// if we're signed in
if ( req.session.auth && req.session.auth.user ){
if ( project.user_id !== req.session.auth.uuid && !project.shared_user_ids.includes(req.session.auth.uuid) ){
project.shared_user_ids.push(req.session.auth.uuid)
await project.save()
}
return res.redirect('/dash/v1')
}
else {
req.session.invite = true
req.session.invite_data = {
invite: invite.id,
project: project.id,
user: user.id,
}
return res.redirect('/dash/v1')
}
}
}
module.exports = exports = v1

@ -5,6 +5,7 @@
*/
const Project = _flitter.model('v1:Project')
const Out = _flitter.model('v1:Out')
const Invite = _flitter.model('v1:Invite')
class v1 {
/*
@ -130,7 +131,7 @@ class v1 {
}
// TODO permission access check
return _flitter.view(res, 'dash_v1:out', {user: req.session.auth.user, out, prettyd:pretty, show_back: true, title: out.brief, title_small: true });
return _flitter.view(res, 'dash_v1:out', {project, user: req.session.auth.user, out, prettyd:pretty, show_back: true, title: out.brief, title_small: true });
}
async out_delete(req, res, next){
@ -264,6 +265,49 @@ class v1 {
return res.redirect('/dash/v1')
}
async project_share_invite(req, res, next){
const project = await Project.findById(req.params.id)
if ( !project ) return _flitter.error(res, 404, {reason: 'Project not found with the specified ID.'})
if ( !project.user_id === req.session.auth.uuid ) return _flitter.error(res, 401, {reason: 'You do not have permission to edit this project.'})
let share_data = {
project_id: project.id,
by_user_id: req.session.auth.uuid,
created_on: Date.now()
}
const share = new Invite(share_data)
await share.save()
return _flitter.view(res, 'dash_v1:invite', {share, project, title: 'Generate Invite Link', show_back: true})
}
async accept_invite(req, res, next){
if ( !req.session.invite ) return res.redirect('/dash/v1')
const invite = await Invite.findById(req.session.invite_data.invite)
if ( !invite ) return _flitter.error(res, 404, {reason: 'This invitation is no longer valid. Sorry.'})
const project = await Project.findById(req.session.invite_data.project)
if ( !project ) return _flitter.error(res, 404, {reason: 'This project no longer exists.'})
const user = await _flitter.model('User').findById(req.session.invite_data.user)
if ( !user ) return _flitter.error(res, 404, {reason: 'This user no longer exists. Sorry.'})
if ( !project.shared_user_ids.includes(req.session.auth.uuid) && !(project.user_id === req.session.auth.uuid) ){
project.shared_user_ids.push(req.session.auth.uuid)
await project.save()
}
invite.used = true
await invite.save()
req.session.invite = false
req.session.invite_data = false
return res.redirect('/dash/v1/project/view/'+project.id)
}
}
module.exports = exports = v1

@ -0,0 +1,13 @@
/*
* Invite Model
* -------------------------------------------------------------
* Put some description here!
*/
const Invite = {
project_id: String,
by_user_id: String,
created_on: Date,
used: { type: Boolean, default: false }
}
module.exports = exports = Invite

@ -9,10 +9,10 @@
* Route-specific middleware should be specified in the corresponding
* routes file.
*/
const Middleware = [
'Debug',
let Middleware = [
]
if ( _flitter.config('server.environment') === 'development' ) Middleware.push('Debug')
module.exports = exports = Middleware

@ -0,0 +1,26 @@
/*
* Invite Middleware
* -------------------------------------------------------------
* Put some description here!
*/
class Invite {
/*
* Run the middleware test.
* This method is required by all Flitter middleware.
* It should either call the next function in the stack,
* or it should handle the response accordingly.
*/
test(req, res, next, args = {}){
if ( req.session.invite && !req.originalUrl.includes('/dash/v1/invitation/accept') ){
return res.redirect('/dash/v1/invitation/accept')
}
/*
* Call the next function in the stack.
*/
next()
}
}
module.exports = Invite

@ -34,6 +34,8 @@ const v1 = {
*/
get: {
// '/': [ controller('Controller_Name').handler_name ],
'/invitation/:id': [ _flitter.controller('api:v1').invite_show ],
'/invitation/:id/accept': [ _flitter.controller('api:v1').invite_accept ],
},
/*

@ -21,7 +21,8 @@ const v1 = {
*/
middleware: [
// mw('Middleware Name'),
_flitter.mw('auth:RequireAuth')
_flitter.mw('auth:RequireAuth'),
_flitter.mw('v1:Invite')
],
/*
@ -44,11 +45,14 @@ const v1 = {
'/project/share/:id/share/:user': [ _flitter.controller('dash:v1').project_share_do ],
'/project/share/:id/revoke/:user': [ _flitter.controller('dash:v1').project_share_revoke ],
'/project/share/:id/transfer/:user': [ _flitter.controller('dash:v1').project_share_transfer ],
'/project/share/:id/invite': [ _flitter.controller('dash:v1').project_share_invite ],
'/out/view/:id': [ _flitter.controller('dash:v1').out_view ],
'/out/delete/:id/:project': [ _flitter.controller('dash:v1').out_delete ],
'/code': [ _flitter.controller('dash:v1').view_code ],
'/invitation/accept': [ _flitter.controller('dash:v1').accept_invite ],
},
/*

@ -0,0 +1,19 @@
html
head
title Project Invitation | DevBug
link(rel='stylesheet' href='/assets/dash_v1.css')
script(src='/assets/dash_v1.js')
body
.page-header
.devbug-header DevBug | v#{devbug.version} #{(project ? " | Project: "+project.name+" | API: "+project.uuid : "")}
h1 Accept Invitation?
ul.navul
li.navli
a.nava(href='/dash/v1') Dashboard Login
.spacer
p You've been invited to view the debugging project "#{project.name}" by #{user.username}.
p To accept this invitation, you must have a DevBug account. You will be redirected to the registration portal.
a.btn(href='/api/v1/invitation/'+invite.id+'/accept') Accept
br
h3 What's DevBug?
p DevBug is a debugging output server used to help developers work more efficiently. Using inline-code clients, developers can output variables and data from their programs. This data is stored in a DevBug project, where it can easily be shared with others.

@ -0,0 +1,7 @@
extends ./template
block content
p You can send this link to someone without a DevBug account to invite them to register.
p Once they register, #{project.name} will be shared with them. This link can only be used once.
h3 Invitation Link
pre
code #{_flitter.config('server.url')+'/api/v1/invitation/'+share.id}

@ -24,6 +24,9 @@ block content
strike Transfer Ownership
br
h2 Share With New User
a.btn(href='/dash/v1/project/share/'+project.id+'/invite') Generate Sharing Link
br
br
table
thead
tr

@ -10,7 +10,8 @@ const server_config = {
},
uploads: {
destination: './uploads'
}
},
url: process.env.SERVER_URL || "localhost",
}

@ -7,4 +7,5 @@ DATABASE_NAME=flitter
DATABASE_AUTH=false
SECRET=changeme
ENVIRONMENT=production
ENVIRONMENT=production
SERVER_URL=http://localhost
Loading…
Cancel
Save