Skip to content
This repository was archived by the owner on Jan 6, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions docs/webapis.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ POST /v1/admin/users/:id - update user settings
POST /v1/admin/users/:id/suspend - suspend a user account
POST /v1/admin/users/:id/unsuspend - unsuspend a user account
GET /v1/admin/archives/:key - get archive information
POST /v1/admin/archives/:key/remove - remove an archive
POST /v1/admin/users/:username/send-email - send an email to the user
```

Expand Down Expand Up @@ -90,7 +91,7 @@ Response when `?view=activity`:
```

Additional query params when `?view=activity`:

- start: For pagination. The key of the event to start after.

### GET /v1/users/:username/:archivename
Expand Down Expand Up @@ -126,7 +127,7 @@ Response body when `?view=activity`:
```

Additional query params when `?view=activity`:

- start: For pagination. The key of the event to start after.

Response body when `?view=popular`:
Expand All @@ -146,7 +147,7 @@ Response body when `?view=popular`:
```

Additional query params when `?view=popular`:

- start: For pagination. Should be an offset.

Response body when `?view=recent`:
Expand All @@ -166,7 +167,7 @@ Response body when `?view=recent`:
```

Additional query params when `?view=recent`:

- start: For pagination. Should be a timestamp.

## Archive APIs
Expand Down
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ module.exports = function (config) {
app.post('/v1/admin/users/:id/unsuspend', cloud.api.admin.unsuspendUser)
app.post('/v1/admin/users/:username/send-email', cloud.api.admin.sendEmail)
app.get('/v1/admin/archives/:key', cloud.api.admin.getArchive)
app.post('/v1/admin/archives/:key/remove', cloud.api.admin.removeArchive)

// (json) error-handling fallback
// =
Expand Down
54 changes: 54 additions & 0 deletions lib/apis/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ const lock = require('../lock')
module.exports = class AdminAPI {
constructor (cloud) {
this.usersDB = cloud.usersDB
this.archivesDB = cloud.archivesDB
this.activityDB = cloud.activityDB
this.archiver = cloud.archiver
this.mailer = cloud.mailer
this.config = cloud.config
Expand Down Expand Up @@ -149,6 +151,58 @@ module.exports = class AdminAPI {
})
}

async removeArchive (req, res) {
// check perms
if (!res.locals.session) throw new UnauthorizedError()
if (!res.locals.session.scopes.includes('admin:dats')) throw new ForbiddenError()

// validate & sanitize input
req.checkBody('key').isDatHash()
;(await req.getValidationResult()).throw()
var { key } = req.body

if (!key) return res.status(422).json({
message: 'Must provide a key',
invalidInputs: true
})

// get the admin user's record
var adminUserRecord = await this.usersDB.getByID(res.locals.session.id)

var release = await Promise.all([lock('users'), lock('archives')])
try {
// get the archiveRecord
var archiveRecord = await this.archivesDB.getExtraByKey(key)

// update the records
for (var i = 0; i < archiveRecord.hostingUsers.length; i++) {
var userID = archiveRecord.hostingUsers[i]
await this.usersDB.removeArchive(userID, key)
await this.archivesDB.removeHostingUser(key, userID)
}
} finally {
release[0]()
release[1]()
}

// record the event
/* dont await */ this.activityDB.writeGlobalEvent({
userid: adminUserRecord.id,
username: adminUserRecord.username,
action: 'del-archive',
params: {key, name: archiveRecord.name}
})

// remove from the swarm
var archive = await this.archivesDB.getByKey(key)
if (!archive.hostingUsers.length) {
await this.archiver.closeArchive(key)
}

// respond
res.status(200).end()
}

async sendEmail (req, res) {
// check perms
if (!res.locals.session) throw new UnauthorizedError()
Expand Down
7 changes: 7 additions & 0 deletions lib/archiver.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ module.exports = class Archiver {
this._swarm(archive, {download: false, upload: false})
await new Promise(resolve => archive.close(resolve))
delete this.archives[key]
} else {
// is archive still loading?
// wait to finish then try to close
if (this.isLoadingArchive(key)) {
await this.loadPromises[key]
return this.closeArchive(key)
}
}
}

Expand Down
1 change: 0 additions & 1 deletion lib/templates/mail/support.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ exports.subject = function (params) {
}

exports.text = function (params) {
console.log(params)
return `
${params.username},\n
\n
Expand Down
40 changes: 39 additions & 1 deletion test/admin.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
var test = require('ava')
var bytes = require('bytes')
var path = require('path')
var createTestServer = require('./lib/server.js')
var { makeDatFromFolder } = require('./lib/dat.js')

var app
var sessionToken, auth
var sessionToken, auth, testDat, testDatKey

test.cb('start test server', t => {
app = createTestServer(async err => {
Expand All @@ -25,6 +27,15 @@ test.cb('start test server', t => {
})
})

test.cb('share test-dat', t => {
makeDatFromFolder(path.join(__dirname, '/scaffold/testdat1'), (err, d, dkey) => {
t.ifError(err)
testDat = d
testDatKey = dkey
t.end()
})
})

async function registerUser (username) {
// register
var res = await app.req.post({
Expand Down Expand Up @@ -366,6 +377,33 @@ test('send support email', async t => {
t.truthy(lastMail.data.text.includes('The message'))
})

test('remove an archive', async t => {

// upload the test archive
var json = {key: testDatKey}
var res = await app.req.post({
uri: '/v1/archives/add',
json: {key: testDatKey},
auth
})

t.is(res.statusCode, 200, '200 added dat')

// remove the archive
var res = await app.req.post({
uri: `/v1/admin/archives/${testDatKey}/remove`,
json: {
key: testDatKey
},
auth
})
t.is(res.statusCode, 200, '200 removed dat')

// check that the archive was removed
var res = await app.req({uri: `/v1/archives/${testDatKey}`, qs: {view: 'status'}, auth})
t.is(res.statusCode, 404, '404 not found')
})

test.cb('stop test server', t => {
app.close(() => {
t.pass('closed')
Expand Down