Skip to content
This repository has been archived by the owner on Oct 22, 2021. It is now read-only.

Commit

Permalink
fix(): #9 #8 Trash by user, keep archives
Browse files Browse the repository at this point in the history
  • Loading branch information
soyuka committed Jul 5, 2015
1 parent 14f942e commit df6bd71
Show file tree
Hide file tree
Showing 13 changed files with 358 additions and 147 deletions.
33 changes: 32 additions & 1 deletion client/scss/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
@import 'foundation/components/tables';
@import 'foundation/components/top-bar';
@import 'foundation/components/visibility';
@import 'foundation/components/sub-nav.scss';
@import 'foundation/components/alert-boxes.scss';

.small {
Expand All @@ -23,8 +22,36 @@

table {
width: 100%;

td input[type="checkbox"] {
margin: 0.80rem 0;
}

}

table.admin {
tr:nth-of-type(even) {
background-color: transparent !important;
}

tr.border-bottom {
border-bottom: 1px solid $gainsboro;
}

td.border-left {
border-left: 1px solid $gainsboro;
}

td.border-right {
border-right: 1px solid $gainsboro;
}

tr.header {
background: $table-even-row-bg !important;
font-weight: bold;
}
}

.columns > .postfix {
padding: 0;
}
Expand All @@ -41,3 +68,7 @@ label.key {
}

}

small > label {
font-size: inherit;
}
6 changes: 4 additions & 2 deletions lib/userSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ module.exports = {
},
admin: {
type: 'boolean',
default: '0',
default: 0,
update: true,
position: 4
},
readonly: {
type: 'boolean',
default: '0',
default: 0,
update: true,
position: 5
},
Expand All @@ -42,12 +42,14 @@ module.exports = {
type: 'string',
default: '',
update: true,
directory: true,
position: 7
},
archive: {
type: 'string',
default: '',
update: true,
directory: true,
position: 8
}
}
11 changes: 10 additions & 1 deletion lib/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ var p = require('path')
var eol = require('os').EOL
var bcrypt = Promise.promisifyAll(require('bcrypt'))
var schema = require('./userSchema.js')
var mkdirp = require('mkdirp')

const saltLength = 9
const keyLength = 25
Expand Down Expand Up @@ -184,7 +185,7 @@ class User {
user[i] = schema[i].default
} else if(schema[i].type == 'boolean') {
user[i] = this.valueToIntegerBool(user[i])
} else if(schema[i].type == 'buffer' && user[i].length) {
} else if(schema[i].type == 'buffer' && user[i].length && typeof user[i] == 'string') {
user[i] = user[i].split(eol).filter(v => v.length > 0)
}
}
Expand Down Expand Up @@ -295,6 +296,14 @@ class User {
if(i == 'password' && crypt === false)
continue;

if(schema[i].directory === true && user[i].length) {
let dir = p.resolve(user.home, user[i])

if(!fs.existsSync(dir)) {
mkdirp.sync(dir)
}
}

this[i] = user[i]
}

Expand Down
18 changes: 17 additions & 1 deletion lib/utils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
var p = require('path')
var Promise = require('bluebird')
var util = require('util')
var fs = require('fs')
var rimraf = Promise.promisify(require('rimraf'))

/**
* Filter names starting with a dot
Expand Down Expand Up @@ -118,4 +120,18 @@ var firstExistingPath = function(paths) {
return false
}

export {noDotFiles, higherPath, extend, buildUrl, sanitize, secureString, firstExistingPath}
/**
* Remove directory content with rimraf on each file
* Skips dot files
* @param string path
* @return Promise
*/
var removeDirectoryContent = function(path) {
return fs.readdirAsync(path)
.filter(noDotFiles)
.map(function(filename) {
return rimraf(p.resolve(path, filename))
})
}

export {noDotFiles, higherPath, extend, buildUrl, sanitize, secureString, firstExistingPath, removeDirectoryContent}
51 changes: 16 additions & 35 deletions routes/admin.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
var debug = require('debug')('explorer:routes:admin')
var Promise = require('bluebird')
var rimraf = Promise.promisify(require('rimraf'))
var prettyBytes = require('pretty-bytes')
var fs = Promise.promisifyAll(require('fs'))
var p = require('path')
var yaml = require('yamljs')

import {noDotFiles, extend} from '../lib/utils.js'
import {noDotFiles, extend, removeDirectoryContent} from '../lib/utils.js'
import {User} from '../lib/users.js'
import {tree} from '../lib/tree.js'
import {trashSize} from './middlewares.js'

function handleSystemError(req, res) {
return function (err) {
Expand All @@ -31,56 +31,37 @@ function validUser(req, res, next) {
return next()
}

function isAdmin(req, res, next) {
if(!req.user.admin)
return res.status(403).send('Forbidden')
function isAdmin(config) {
return function(req, res, next) {
if(!req.user.admin)
return res.status(403).send('Forbidden')

return next()
res.locals.config = config
res.locals.ymlConfig = yaml.stringify(config, 2, 4)

return next()
}
}

var Admin = function(app) {
let admin = require('express').Router()
let config = app.get('config')
admin.use(isAdmin)

admin.get('/', function(req, res) {

if(config.remove.method !== 'mv')
return res.renderBody('admin', {users: req.users.users, remove: false, trash_size: '0 B'})

tree(config.remove.trash, {maxDepth: 1})
.then(function(tree) {

if(tree.tree.length == 0)
return res.renderBody('admin', {users: req.users.users, remove: true, trash_size: '0 B'})

let size = 0;

for(var i in tree.tree) {
size += tree.tree[i].size
}

debug('Trash size %s', size)

return res.renderBody('admin', {users: req.users.users, remove: true, trash_size: prettyBytes(size)})
})
admin.use(isAdmin(config))

admin.get('/', trashSize(config), function(req, res) {
return res.renderBody('admin', {users: req.users.users, remove: config.remove && config.remove.method == 'mv'})
})

admin.post('/trash', function(req, res) {

debug('Empty trash %s', config.remove.trash)

fs.readdirAsync(config.remove.trash)
.filter(noDotFiles)
.map(function(filename) {
return rimraf(p.resolve(config.remove.trash, filename))
})
removeDirectoryContent(config.remove.trash)
.then(function() {
return res.redirect('back')
})
.catch(handleSystemError)

})

admin.get('/create', function(req, res) {
Expand Down
121 changes: 121 additions & 0 deletions routes/middlewares.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
var p = require('path')
var debug = require('debug')('explorer:middlewares')
var prettyBytes = require('pretty-bytes')

import {tree} from '../lib/tree.js'
import {sort} from '../lib/sort.js'
import {extend, buildUrl, secureString, higherPath} from '../lib/utils.js'

function trashSize(config) {

return function (req, res, next) {

res.locals.trashSize = '0 B'

if(!config.remove || !config.remove.method == 'mv') {
return next()
}

let v = config.remove.trash

if(req.user.trash) {
v = p.resolve(req.user.home, req.user.trash)
}

tree(v, {maxDepth: 1})
.then(function(tree) {

if(tree.tree.length == 0) {
return next()
}

let size = 0;

for(var i in tree.tree) {
size += tree.tree[i].size
}

debug('Trash size %s', size)

res.locals.trashSize = prettyBytes(size)

return next()
})
.catch(next)
}
}

/**
* Prepare tree locals et validate queries
* @param config
* @return function middleware(req, res, next)
*/
function prepareTree(config) {
return function(req, res, next) {
//should be an app.param
if(!req.query.page || req.query.page < 0)
req.query.page = 1

req.query.page = parseInt(req.query.page)

if(req.query.sort) {
if(!sort.hasOwnProperty(req.query.sort)) {
req.query.sort = null
}
}

if(!~['asc', 'desc'].indexOf(req.query.order)) {
req.query.order = 'asc'
}

if(!req.query.path)
req.query.path = './'

if(req.query.search && config.search.method !== 'native') {
req.query.search = secureString(req.query.search)
}

res.locals = extend(res.locals, {
search: req.query.search,
sort: req.query.sort || '',
order: req.query.order || '',
page: req.query.page,
root: p.resolve(req.user.home),
path: higherPath(req.user.home, req.query.path),
parent: higherPath(req.user.home, p.resolve(req.query.path, '..')),
buildUrl: buildUrl
})

req.options = extend(
res.locals,
config.tree,
config.pagination,
{remove: config.remove},
{archive: config.archive}
)

if(req.user.trash) {
req.options.remove.trash = p.resolve(req.user.home, req.user.trash)
}

if(!!req.user.readonly === true || req.options.path == req.options.remove.trash) {
res.locals.canRemove = false
} else {
res.locals.canRemove = config.remove && config.remove.method ? true : false
}

if(req.user.archive) {
req.options.archive.temp = p.resolve(req.user.home, req.user.archive)
}

if(res.locals.sort)
req.options.sortMethod = sort[res.locals.sort](req.options)

debug('Options: %o', req.options)

return next()
}
}


export {trashSize, prepareTree}
13 changes: 11 additions & 2 deletions routes/settings.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
var Promise = require('bluebird')

import {User} from '../lib/users.js'
import {trashSize, prepareTree} from './middlewares.js'

function handleSystemError(req, res) {
return function (err) {
Expand All @@ -24,8 +25,14 @@ function updateSettings(req, res) {
if(!u) {
return handleSystemError(req,res)('User not found')
}

let ignore = ['home', 'admin', 'readonly', 'ignore']

if(req.user.readonly) {
ignore.concat(['trash', 'archive'])
}

u.update(req.body, ['home', 'admin', 'readonly'])
u.update(req.body, ignore)
.then(function(user) {
return req.users.put(user)
.then(function() {
Expand All @@ -37,7 +44,9 @@ function updateSettings(req, res) {
}

var Settings = function(app) {
app.get('/settings', settings)
let config = app.get('config')

app.get('/settings', trashSize(config), prepareTree(config), settings)
app.put('/settings', updateSettings)

return app
Expand Down
Loading

0 comments on commit df6bd71

Please sign in to comment.