diff --git a/app/MiscUnit.js b/app/MiscUnit.js index cac18c7..a4d21e6 100644 --- a/app/MiscUnit.js +++ b/app/MiscUnit.js @@ -10,7 +10,7 @@ const Unit = require('libflitter/Unit') * other units in the stack. */ class MiscUnit extends Unit { - + /* * Initializes the unit class. * This is called OUTSIDE of a Flitter context, @@ -19,10 +19,10 @@ class MiscUnit extends Unit { */ constructor(){ super() - - + + } - + /* * Initialize the actual Unit. * This is where most of the changes will go. @@ -32,15 +32,75 @@ class MiscUnit extends Unit { * model(), etc. work. */ async go(app, context){ - + // do stuff here - + global.devbug = { + version: '0.2.0', + code: { + php: ` $what ]; +\t\t} +\t\telse { +\t\t\t$dev_outs[$group][$key] = $what; +\t\t} +\t} +\telse { +\t\t$dev_outs[$key] = $what; +\t} +} +function breakpoint($html = false, $name = null){ +\tglobal $dev_outs; +\t$devbug = "http://CHANGEME:8000/"; +\t$project_api_key = "CHANGEME"; +\t$bt = debug_backtrace(); +\t$caller = array_shift($bt); + +\tif ( !$html ){ +\t\tvar_dump([($item ? $item : $caller), 'outs' => $dev_outs]); +\t} +\telse { +\t\techo "
";
+\t\tvar_dump([($item ? $item : $caller), 'outs' => $dev_outs]);
+\t\techo "
";
+\t}
+
+\t// Send to devbug server
+\t$ch = curl_init();
+\t$url = $devbug.'api/v1/out/'.$project_api_key;
+\tvar_dump($url);
+\tcurl_setopt($ch, CURLOPT_URL, $url);
+\tcurl_setopt($ch, CURLOPT_POST, 1);
+\tcurl_setopt($ch, CURLOPT_POSTFIELDS, [
+\t 'data' => json_encode([
+\t 'brief' => ($name ? $name : 'Breakpoint').': '.$caller['file'].': '.$caller['line'],
+\t 'data' => $dev_outs,
+\t ])
+\t]);
+
+\tcurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+\t
+\t$odata = curl_exec($ch);
+
+\texit();
+}
+// ===========================================================`
+ }
+ }
+
}
-
+
name(){
return "misc"
}
}
-module.exports = exports = MiscUnit
\ No newline at end of file
+module.exports = exports = MiscUnit
diff --git a/app/assets/dash_v1.css b/app/assets/dash_v1.css
index ffd882d..3fbe3c6 100644
--- a/app/assets/dash_v1.css
+++ b/app/assets/dash_v1.css
@@ -2,7 +2,7 @@
@import url('https://fonts.googleapis.com/css?family=Source+Code+Pro');
html {
- font-family: "Source Sans Pro";
+ font-family: "Source Sans Pro", sans-serif;
}
table, th, td {
@@ -17,7 +17,7 @@ th, td {
}
pre, code {
- font-family: "Source Code Pro";
+ font-family: "Source Code Pro", monospace;
font-size: 10pt;
}
@@ -25,11 +25,44 @@ a {
color: #004d4d;
}
+.page-header {
+ background: #ccdddd;
+ width: 100%;
+ margin: 0;
+ padding: 0;
+ padding-left: 20px;
+ padding-right: 20px;
+ position: fixed;
+ top: 0;
+ left: 0;
+}
+
+.devbug-header {
+ background: #509d9d;
+ width: 100%;
+ position: relative;
+ margin: 0;
+ padding: 5px;
+ padding-left: 20px;
+ margin-left: -20px;
+ color: white;
+}
+
+.spacer {
+ min-height: 165px;
+}
+
.navul {
list-style-type: none;
margin: 0;
- padding: 5;
- margin-bottom: 20px;
+ padding: 0;
+ padding-left: 20px;
+ padding-top: 10px;
+ padding-bottom: 10px;
+ margin-left: -20px;
+ position: relative;
+ width: 100%;
+ background: #004d4d;
}
.navli {
@@ -41,7 +74,7 @@ a {
}
.navli:hover {
- background: #004d4d;
+ background: #509d9d;
}
.nava {
@@ -52,4 +85,11 @@ a {
.nava:hover {
color: #eee;
-}
\ No newline at end of file
+}
+
+pre {outline: 1px solid #ccc; padding: 5px; margin: 5px; }
+.string { color: darkslateblue; }
+.number { color: darkorange; }
+.boolean { color: blue; }
+.null { color: magenta; }
+.key { color: green; }
diff --git a/app/assets/dash_v1.js b/app/assets/dash_v1.js
new file mode 100644
index 0000000..e5daf25
--- /dev/null
+++ b/app/assets/dash_v1.js
@@ -0,0 +1,29 @@
+function output(inp) {
+ document.body.appendChild(document.createElement('pre')).innerHTML = inp;
+}
+
+function syntaxHighlight(json) {
+ json = JSON.stringify(JSON.parse(json.replace(/"/g, '"')), undefined, 4)
+ json = json.replace(/&/g, '&').replace(//g, '>');
+ return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
+ var cls = 'number';
+ if (/^"/.test(match)) {
+ if (/:$/.test(match)) {
+ cls = 'key';
+ } else {
+ cls = 'string';
+ }
+ } else if (/true|false/.test(match)) {
+ cls = 'boolean';
+ } else if (/null/.test(match)) {
+ cls = 'null';
+ }
+ return '' + match + '';
+ });
+}
+
+function from_server(json_string){
+ console.log(json_string)
+ json_string = JSON.parse(json_string.replace(/"/g, '"'))
+ window.devbug = json_string
+}
diff --git a/app/controllers/api/v1.controller.js b/app/controllers/api/v1.controller.js
index 3ef5417..503d5c9 100644
--- a/app/controllers/api/v1.controller.js
+++ b/app/controllers/api/v1.controller.js
@@ -38,9 +38,22 @@ class v1 {
error: 'Missing data.'
})
}
-
- const data = JSON.parse(req.body.data)
-
+
+ let data
+ try {
+ data = JSON.parse(req.body.data)
+ }
+ catch (e){
+ return res.status(400).send({
+ success: false,
+ error: 'Invalid JSON.'
+ })
+ }
+
+ if ( !data.brief ){
+ data.brief = 'Breakpoint. (No Message.)'
+ }
+
const out = new Out({
brief: data.brief,
data: JSON.stringify(data.data),
@@ -55,4 +68,4 @@ class v1 {
}
}
-module.exports = exports = v1
\ No newline at end of file
+module.exports = exports = v1
diff --git a/app/controllers/dash/v1.controller.js b/app/controllers/dash/v1.controller.js
index 2f76580..6e1c8f4 100644
--- a/app/controllers/dash/v1.controller.js
+++ b/app/controllers/dash/v1.controller.js
@@ -13,6 +13,16 @@ class v1 {
async main(req, res){
const projects = await Project.find({ archived: false, user_id: req.session.auth.uuid })
+
+ let find = {
+ shared_user_ids: {
+ $elemMatch: {
+ $eq: req.session.auth.uuid
+ }
+ }
+ }
+
+ const shared_projects = await Project.find(find)
/*
* Return the main view.
@@ -20,7 +30,7 @@ class v1 {
* View parameters can be passed as an optional third
* argument to the view() method.
*/
- return _flitter.view(res, 'dash_v1:main', { projects })
+ return _flitter.view(res, 'dash_v1:main', { projects, shared_projects, user: req.session.auth.user })
}
new_project_show(req, res, next){
@@ -30,20 +40,30 @@ class v1 {
async project_edit_show(req, res, next){
const project = await Project.findById(req.params.id)
if ( !project ){
- return _flitter.error(res, 404, 'Project not found with the specified ID.')
+ return _flitter.error(res, 404, {reason: 'Project not found with the specified ID.'})
+ }
+
+ // check access perms
+ if ( !(project.user_id === req.session.auth.uuid) ){
+ return _flitter.error(res, 401, {reason: 'You do not have permissions to edit this project.'})
}
- return _flitter.view(res, 'dash_v1:project', { show_back: true, title: 'Update Project', project_name: project.name})
+ return _flitter.view(res, 'dash_v1:project', { show_back: true, title: 'Update Project', project_name: project.name, user: req.session.auth.user })
}
async project_edit_do(req, res, next){
const project = await Project.findById(req.params.id)
if ( !project ){
- return _flitter.error(res, 404, 'Project not found with the specified ID.')
+ return _flitter.error(res, 404, {reason: 'Project not found with the specified ID.'})
}
if ( !req.body || !req.body.name ){
- return _flitter.view(res, 'dash_v1:project', {show_back: true, title: 'Update Project', project_name: project.name, errors: ['Project name is required.']})
+ return _flitter.view(res, 'dash_v1:project', {user: req.session.auth.user, show_back: true, title: 'Update Project', project_name: project.name, errors: ['Project name is required.']})
+ }
+
+ // check access perms
+ if ( !(project.user_id === req.session.auth.uuid) ){
+ return _flitter.error(res, 401, {reason: 'Project not found with the specified ID.'})
}
project.name = req.body.name
@@ -54,7 +74,7 @@ class v1 {
async new_project_do(req, res, next){
if ( !req.body.name ){
- return _flitter.view(res, 'dash_v1:project', {show_back: true, title: 'Create Project', errors: ['Project name is required.']})
+ return _flitter.view(res, 'dash_v1:project', {user: req.session.auth.user, show_back: true, title: 'Create Project', errors: ['Project name is required.']})
}
const project = new Project({
@@ -76,31 +96,78 @@ class v1 {
const project = await Project.findById(req.params.id)
if ( !project ){
- _flitter.error(res, 404, 'Project not found.')
+ return _flitter.error(res, 404, {reason: 'Project not found with the specified ID.'})
}
const outs = await Out.find({ project_id: project.id }).sort('-created')
-
- return _flitter.view(res, 'dash_v1:view', { project, outs, show_back: true, title: 'View: '+project.name })
+
+ if ( !(project.user_id === req.session.auth.uuid) && !(project.shared_user_ids.includes(req.session.auth.uuid)) ){
+ return _flitter.error(res, 401, {reason: 'You do not have permission to view this project.'})
+ }
+
+ return _flitter.view(res, 'dash_v1:view', {user: req.session.auth.user, project, outs, show_back: true, title: 'View: '+project.name })
}
async out_view(req, res, next){
const out = await Out.findById(req.params.id)
+
+ if ( !out ){
+ return _flitter.error(res, 404, {reason: 'Output not found with the specified ID.'})
+ }
+
+ let pretty
+ try {
+ pretty = JSON.stringify(JSON.parse(out.data), null, 4)
+ }
+ catch (e){
+ return _flitter.error(res, 500, {reason: 'Unable to parse output data. Data contains invalid JSON.'})
+ }
+
+ const project = await Project.findById(out.project_id)
- console.log(out.data)
-
- const pretty = JSON.stringify(JSON.parse(out.data), null, 4)
-
+ if ( !project || (!(project.user_id === req.session.auth.uuid) && !(project.shared_user_ids.includes(req.session.auth.uuid))) ){
+ return _flitter.error(res, 401, {reason: 'You do not have permission to view this project.'})
+ }
+
// TODO permission access check
- return _flitter.view(res, 'dash_v1:out', {out, prettyd:pretty, show_back: true, title: out.brief, title_small: true });
+ return _flitter.view(res, 'dash_v1:out', {user: req.session.auth.user, out, prettyd:pretty, show_back: true, title: out.brief, title_small: true });
}
+
+ async out_delete(req, res, next){
+ const out = await Out.findById(req.params.id)
- project_delete_show(req, res, next){
- return _flitter.view(res, 'dash_v1:confirm', {show_back: true, title: 'Are you sure?', text: 'Deleting this project will remove all stored breakpoint data. This action cannot be undone.', destination: '/dash/v1/project/delete/'+req.params.id})
+ const project = await Project.findById(req.params.project)
+ if ( !project || ( !(project.user_id === req.session.auth.uuid) ) ){
+ return _flitter.error(res, 401, {reason: 'You do not have permission to edit this project.'})
+ }
+
+ if ( out ){
+ await out.delete()
+ }
+
+ return res.redirect('/dash/v1/project/view/'+req.params.project)
+ }
+
+ async project_delete_show(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.'})
+ }
+
+ return _flitter.view(res, 'dash_v1:confirm', {user: req.session.auth.user, project, show_back: true, title: 'Are you sure?', text: 'Deleting this project will remove all stored breakpoint data. This action cannot be undone.', destination: '/dash/v1/project/delete/'+req.params.id})
}
async project_delete_do(req, res, next){
const project = await Project.findById(req.params.id)
+
+ if ( project && ( !(project.user_id === req.session.auth.uuid) ) ){
+ return _flitter.error(res, 401, {reason: 'You do not have permission to edit this project.'})
+ }
+
if ( project ){
const outs = await Out.find({project_id: project.id})
@@ -113,6 +180,90 @@ class v1 {
return res.redirect('/dash/v1')
}
+
+ view_code(req, res, next){
+ return _flitter.view(res, 'dash_v1:code', { user: req.session.auth.user, title: 'Inline Code Snippets' })
+ }
+
+ async project_share_show(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 find = {
+ uuid: { $nin: [] }
+ }
+
+ find.uuid.$nin.push(req.session.auth.uuid)
+ find.uuid.$nin = find.uuid.$nin.concat(project.shared_user_ids)
+
+ const to_share = await _flitter.model('User').find(find)
+
+ find = {
+ uuid: { $in: find.uuid.$nin }
+ }
+
+ const shared = await _flitter.model('User').find(find)
+
+ return _flitter.view(res, 'dash_v1:share', { user: req.session.auth.user, sharing: { to_share, shared }, project, title: 'Share Project: '+project.name, show_back: true })
+ }
+
+ async project_share_do(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.'})
+
+ const target_user = await _flitter.model('User').findOne({uuid: req.params.user})
+ if ( !target_user ) return _flitter.error(res, 404, {reason: 'User 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."})
+
+ if ( !(project.user_id === target_user.uuid) && !(project.shared_user_ids.includes(target_user.uuid)) ){
+ project.shared_user_ids.push(target_user.uuid)
+ await project.save()
+ }
+
+ return res.redirect('/dash/v1/project/share/'+project.id)
+ }
+
+ async project_share_revoke(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.'})
+
+ const target_user = await _flitter.model('User').findOne({uuid: req.params.user})
+ if ( !target_user ) return _flitter.error(res, 404, {reason: 'User not found with the specified ID.'})
+
+ if ( !(project.user_id === req.session.auth.uuid || project.shared_user_ids.includes(req.session.auth.uuid)) ) return _flitter.error(res, 401, {reason: "You do not have permission to edit this project."})
+
+ const to_dash = project.shared_user_ids.includes(req.session.auth.uuid)
+
+ if ( !(target_user.uuid === project.user_id) && (project.shared_user_ids.includes(target_user.uuid)) ){
+ project.shared_user_ids.splice(project.shared_user_ids.indexOf(target_user.uuid), 1)
+ await project.save()
+ }
+
+ if ( to_dash ) return res.redirect('/dash/v1')
+
+ return res.redirect('/dash/v1/project/share/'+project.id)
+ }
+
+ async project_share_transfer(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.'})
+
+ const target_user = await _flitter.model('User').findOne({uuid: req.params.user})
+ if ( !target_user ) return _flitter.error(res, 404, {reason: 'User 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.'})
+
+ project.user_id = target_user.uuid
+ project.shared_user_ids.push(req.session.auth.uuid)
+
+ await project.save()
+
+ return res.redirect('/dash/v1')
+ }
}
-module.exports = exports = v1
\ No newline at end of file
+module.exports = exports = v1
diff --git a/app/routing/routers/dash/v1.routes.js b/app/routing/routers/dash/v1.routes.js
index ed0b329..0f08ebc 100644
--- a/app/routing/routers/dash/v1.routes.js
+++ b/app/routing/routers/dash/v1.routes.js
@@ -12,7 +12,7 @@ const v1 = {
* '/login' becomes '/auth/login'
*/
prefix: '/dash/v1',
-
+
/*
* Define middleware that should be applied to all
* routes defined in this file. Middleware should be
@@ -34,15 +34,21 @@ const v1 = {
* controller() calls get methods in Flitter controllers
*/
get: {
- // '/': [ controller('Controller_Name').handler_name ],
'/': [ _flitter.controller('dash:v1').main ],
'/project/new': [ _flitter.controller('dash:v1').new_project_show ],
'/project/view/:id': [ _flitter.controller('dash:v1').project_view ],
'/project/delete/:id': [ _flitter.controller('dash:v1').project_delete_show ],
'/project/edit/:id': [ _flitter.controller('dash:v1').project_edit_show ],
+ '/project/share/:id': [ _flitter.controller('dash:v1').project_share_show ],
+ '/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 ],
'/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 ],
},
/*
@@ -61,4 +67,4 @@ const v1 = {
},
}
-module.exports = v1
\ No newline at end of file
+module.exports = v1
diff --git a/app/views/dash_v1/code.pug b/app/views/dash_v1/code.pug
new file mode 100644
index 0000000..348c12f
--- /dev/null
+++ b/app/views/dash_v1/code.pug
@@ -0,0 +1,15 @@
+extends ./template
+block content
+ p
+ | These code snippets are designed to be included in-line. You can store outputs using the
+ code out()
+ | function. Then, call the
+ code breakpoint()
+ | function to send those outputs to DevBug.
+ p
+ | You'll need to ensure that the DevBug server URL and Project API Key are correct. These are local variables in the
+ code breakpoint()
+ | function.
+ h2 PHP
+ pre
+ code #{devbug.code.php}
diff --git a/app/views/dash_v1/main.pug b/app/views/dash_v1/main.pug
index 1a3a884..30a26dd 100644
--- a/app/views/dash_v1/main.pug
+++ b/app/views/dash_v1/main.pug
@@ -17,7 +17,27 @@ block content
ul(style='list-style-type: none; margin: 0; padding: 0;')
li
a.action(href='/dash/v1/project/view/'+project.id) View
+ li
+ a.action(href='/dash/v1/project/share/'+project.id) Share
li
a.action(href='/dash/v1/project/delete/'+project.id) Delete
li
a.action(href='/dash/v1/project/edit/'+project.id) Edit
+
+ if shared_projects
+ h3 Projects Shared With Me
+ table
+ thead
+ tr
+ th(scope='col' style='min-width: 250px') Name
+ th(scope='col') Actions
+ tbody
+ each project in shared_projects
+ tr
+ td #{project.name}
+ td
+ ul(style='list-style-type: none; margin: 0; padding: 0;')
+ li
+ a.action(href='/dash/v1/project/view/'+project.id) View
+ li
+ a.action(href='/dash/v1/project/share/'+project.id+'/revoke/'+user.uuid) Remove
diff --git a/app/views/dash_v1/out.pug b/app/views/dash_v1/out.pug
index a937236..f3af085 100644
--- a/app/views/dash_v1/out.pug
+++ b/app/views/dash_v1/out.pug
@@ -1,5 +1,4 @@
extends ./template
block content
- pre
- code
- div #{prettyd}
\ No newline at end of file
+ script(src='/assets/dash_v1.js')
+ script output(syntaxHighlight(`#{prettyd}`));
diff --git a/app/views/dash_v1/share.pug b/app/views/dash_v1/share.pug
new file mode 100644
index 0000000..bb9f5dd
--- /dev/null
+++ b/app/views/dash_v1/share.pug
@@ -0,0 +1,45 @@
+extends ./template
+block content
+ h2 Shared With
+ table
+ thead
+ tr
+ th(scope='col' style='min-width: 250px') Username
+ th(scope='col') Actions
+ tbody
+ each user in sharing.shared
+ tr
+ td #{(user.uuid === project.user_id ? user.username + " (Owner)" : user.username)}
+ td
+ ul(style='list-style-type: none; margin: 0; padding: 0;')
+ if !(user.uuid === project.user_id)
+ li
+ a.action(href='/dash/v1/project/share/'+project.id+'/revoke/'+user.uuid) Revoke
+ li
+ a.action(href='/dash/v1/project/share/'+project.id+'/transfer/'+user.uuid) Transfer Ownership
+ else
+ li
+ strike Revoke
+ li
+ strike Transfer Ownership
+ br
+ h2 Share With New User
+ table
+ thead
+ tr
+ th(scope='col' style='min-width: 250px') Username
+ th(scope='col') Actions
+ tbody
+ each user in sharing.to_share
+ tr
+ td #{(user.uuid === project.user_id ? user.username + " (Owner)" : user.username)}
+ td
+ ul(style='list-style-type: none; margin: 0; padding: 0;')
+ if !(user.uuid === project.user_id)
+ li
+ a.action(href='/dash/v1/project/share/' + project.id + '/share/'+user.uuid) Share
+ else
+ li
+ strike Share
+ li
+ a.action(href='/dash/v1/project/share/' + project.id + '/transfer/' + user.uuid) Transfer Ownership
diff --git a/app/views/dash_v1/template.pug b/app/views/dash_v1/template.pug
index d8a8a33..bd48b35 100644
--- a/app/views/dash_v1/template.pug
+++ b/app/views/dash_v1/template.pug
@@ -2,17 +2,23 @@ html
head
title #{(title ? title+' | DevBug' : 'DevBug Dashboard')}
link(rel='stylesheet' href='/assets/dash_v1.css')
+ script(src='/assets/dash_v1.js')
body
- if title_small
- h3 #{(title ? title+' | DevBug' : 'DevBug Dashboard')}
- else
- h1 #{(title ? title+' | DevBug' : 'DevBug Dashboard')}
- ul.navul
- li.navli
- a.nava(href='/dash/v1') Home
- li.navli
- a.nava(href='/auth/logout') Logout
- if show_back
+ .page-header
+ .devbug-header DevBug | v#{devbug.version} #{(user ? " | User: "+user.username : "")} #{(project ? " | Project: "+project.name+" | API: "+project.uuid : "")} #{((_flitter.config('server.environment') === 'development') ? " | Development" : "" )}
+ if title_small
+ h3 #{(title ? title : 'Dashboard')}
+ else
+ h1 #{(title ? title : 'Dashboard')}
+ ul.navul
li.navli
- a.nava(href='javascript:window.history.back()') Back
- block content
\ No newline at end of file
+ a.nava(href='/dash/v1') Home
+ li.navli
+ a.nava(href='/dash/v1/code') Code Snippets
+ li.navli
+ a.nava(href='/auth/logout') Logout
+ if show_back
+ li.navli
+ a.nava(href='javascript:window.history.back()') Back
+ .spacer
+ block content
diff --git a/app/views/dash_v1/view.pug b/app/views/dash_v1/view.pug
index 5790aa0..3a60f3b 100644
--- a/app/views/dash_v1/view.pug
+++ b/app/views/dash_v1/view.pug
@@ -17,4 +17,4 @@ block content
li
a.action(href='/dash/v1/out/view/'+out.id) View
li
- a.action(href='/dash/v1/out/delete/'+out.id) Delete
\ No newline at end of file
+ a.action(href='/dash/v1/out/delete/'+out.id+'/'+project.id) Delete
diff --git a/app/views/errors/401.pug b/app/views/errors/401.pug
new file mode 100644
index 0000000..b725b51
--- /dev/null
+++ b/app/views/errors/401.pug
@@ -0,0 +1,33 @@
+html
+ head
+ title Access Denied | Flitter
+ style(type="text/css").
+ @import url('https://fonts.googleapis.com/css?family=Rajdhani');
+ html,
+ body {
+ height: 100%;
+ overflow-y: hidden;
+ background-color: #c7dbdf;
+ }
+
+ .flitter-container {
+ height: 60%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .flitter-image {
+ height: 150px;
+ }
+
+ .flitter-name {
+ font-family: "Rajdhani";
+ font-size: 36pt;
+ margin-left: 35px;
+ color: #00323d;
+ }
+body
+ .flitter-container
+ img.flitter-image(src="/assets/flitter.png")
+ p.flitter-name Access Denied: #{(reason ? reason : "Resource Not Found.")}
diff --git a/app/views/errors/404.pug b/app/views/errors/404.pug
index 58d3667..dea1f5c 100644
--- a/app/views/errors/404.pug
+++ b/app/views/errors/404.pug
@@ -23,11 +23,11 @@ html
.flitter-name {
font-family: "Rajdhani";
- font-size: 50pt;
+ font-size: 36pt;
margin-left: 35px;
color: #00323d;
}
body
.flitter-container
img.flitter-image(src="/assets/flitter.png")
- p.flitter-name 404: Page Not Found
\ No newline at end of file
+ p.flitter-name 404: #{(reason ? reason : "Resource Not Found.")}