#103: API documentation for /user and /vocabulary

This commit is contained in:
jendib 2016-05-10 23:30:28 +02:00
parent e631aa0e8a
commit e181b7d24b
No known key found for this signature in database
GPG Key ID: 06EE7F699579166F
7 changed files with 311 additions and 59 deletions

View File

@ -21,6 +21,29 @@ import com.sismics.util.filter.TokenBasedSecurityFilter;
* @author jtremeaux * @author jtremeaux
*/ */
public abstract class BaseResource { public abstract class BaseResource {
/**
* @apiDefine admin Admin
* Only the admin user can access this resource
*/
/**
* @apiDefine user Authenticated user
* All authenticated users can access this resource
*/
/**
* @apiDefine none Anonymous user
* This resource can be accessed anonymously
*/
/**
* @apiDefine server Server error
*/
/**
* @apiDefine client Client error
*/
/** /**
* Injects the HTTP request. * Injects the HTTP request.
*/ */

View File

@ -67,7 +67,21 @@ import com.sismics.util.totp.GoogleAuthenticatorKey;
public class UserResource extends BaseResource { public class UserResource extends BaseResource {
/** /**
* Creates a new user. * Creates a new user.
* *
* @api {put} /user Register a new user
* @apiName PutUser
* @apiGroup User
* @apiParam {String{3..50}} username Username
* @apiParam {String{8..50}} password Password
* @apiParam {String{1..100}} email E-mail
* @apiParam {Number} storage_quota Storage quota (in bytes)
* @apiSuccess {String} status Status OK
* @apiError (server) PrivateKeyError Error while generating a private key
* @apiError (client) AlreadyExistingUsername Login already used
* @apiError (server) UnknownError Unknown server error
* @apiPermission admin
* @apiVersion 1.0.0
*
* @param username User's username * @param username User's username
* @param password Password * @param password Password
* @param email E-Mail * @param email E-Mail
@ -88,7 +102,7 @@ public class UserResource extends BaseResource {
username = ValidationUtil.validateLength(username, "username", 3, 50); username = ValidationUtil.validateLength(username, "username", 3, 50);
ValidationUtil.validateAlphanumeric(username, "username"); ValidationUtil.validateAlphanumeric(username, "username");
password = ValidationUtil.validateLength(password, "password", 8, 50); password = ValidationUtil.validateLength(password, "password", 8, 50);
email = ValidationUtil.validateLength(email, "email", 3, 50); email = ValidationUtil.validateLength(email, "email", 1, 100);
Long storageQuota = ValidationUtil.validateLong(storageQuotaStr, "storage_quota"); Long storageQuota = ValidationUtil.validateLong(storageQuotaStr, "storage_quota");
ValidationUtil.validateEmail(email, "email"); ValidationUtil.validateEmail(email, "email");
@ -115,7 +129,7 @@ public class UserResource extends BaseResource {
if ("AlreadyExistingUsername".equals(e.getMessage())) { if ("AlreadyExistingUsername".equals(e.getMessage())) {
throw new ServerException("AlreadyExistingUsername", "Login already used", e); throw new ServerException("AlreadyExistingUsername", "Login already used", e);
} else { } else {
throw new ServerException("UnknownError", "Unknown Server Error", e); throw new ServerException("UnknownError", "Unknown server error", e);
} }
} }
@ -126,8 +140,17 @@ public class UserResource extends BaseResource {
} }
/** /**
* Updates user informations. * Updates the current user informations.
* *
* @api {post} /user Update the current user
* @apiName PostUser
* @apiGroup User
* @apiParam {String{8..50}} password Password
* @apiParam {String{1..100}} email E-mail
* @apiSuccess {String} status Status OK
* @apiPermission user
* @apiVersion 1.0.0
*
* @param password Password * @param password Password
* @param email E-Mail * @param email E-Mail
* @return Response * @return Response
@ -142,7 +165,7 @@ public class UserResource extends BaseResource {
// Validate the input data // Validate the input data
password = ValidationUtil.validateLength(password, "password", 8, 50, true); password = ValidationUtil.validateLength(password, "password", 8, 50, true);
email = ValidationUtil.validateLength(email, "email", null, 100, true); email = ValidationUtil.validateLength(email, "email", 1, 100, true);
// Update the user // Update the user
UserDao userDao = new UserDao(); UserDao userDao = new UserDao();
@ -165,8 +188,20 @@ public class UserResource extends BaseResource {
} }
/** /**
* Updates user informations. * Updates a user informations.
* *
* @api {post} /user/:username Update a user
* @apiName PostUserUsername
* @apiGroup User
* @apiParam {String} username Username
* @apiParam {String{8..50}} password Password
* @apiParam {String{1..100}} email E-mail
* @apiParam {Number} storage_quota Storage quota (in bytes)
* @apiSuccess {String} status Status OK
* @apiError (client) UserNotFound User not found
* @apiPermission admin
* @apiVersion 1.0.0
*
* @param username Username * @param username Username
* @param password Password * @param password Password
* @param email E-Mail * @param email E-Mail
@ -186,7 +221,7 @@ public class UserResource extends BaseResource {
// Validate the input data // Validate the input data
password = ValidationUtil.validateLength(password, "password", 8, 50, true); password = ValidationUtil.validateLength(password, "password", 8, 50, true);
email = ValidationUtil.validateLength(email, "email", null, 100, true); email = ValidationUtil.validateLength(email, "email", 1, 100, true);
// Check if the user exists // Check if the user exists
UserDao userDao = new UserDao(); UserDao userDao = new UserDao();
@ -218,8 +253,17 @@ public class UserResource extends BaseResource {
} }
/** /**
* Checks if a username is available. Search only on active accounts. * Checks if a username is available.
* * Search only on active accounts.
*
* @api {get} /user/check_username Check username availability
* @apiName GetUserCheckUsername
* @apiGroup User
* @apiParam {String} username Username
* @apiSuccess {String} status Status OK or KO
* @apiPermission none
* @apiVersion 1.0.0
*
* @param username Username to check * @param username Username to check
* @return Response * @return Response
*/ */
@ -244,7 +288,21 @@ public class UserResource extends BaseResource {
/** /**
* This resource is used to authenticate the user and create a user session. * This resource is used to authenticate the user and create a user session.
* The "session" is only used to identify the user, no other data is stored in the session. * The "session" is only used to identify the user, no other data is stored in the session.
* *
* @api {post} /user/login Login a user
* @apiDescription This resource creates an authentication token and gives it back in a cookie.
* All authenticated resources will check this cookie to find the user currently logged in.
* @apiName PostUserLogin
* @apiGroup User
* @apiParam {String} username Username
* @apiParam {String} password Password
* @apiParam {String} code TOTP validation code
* @apiParam {Boolean} remember If true, create a long lasted token
* @apiSuccess {String} auth_token A cookie named auth_token containing the token ID
* @apiError (client) ValidationCodeRequired A TOTP validation code is required
* @apiPermission none
* @apiVersion 1.0.0
*
* @param username Username * @param username Username
* @param password Password * @param password Password
* @param longLasted Remember the user next time, create a long lasted session. * @param longLasted Remember the user next time, create a long lasted session.
@ -309,7 +367,16 @@ public class UserResource extends BaseResource {
/** /**
* Logs out the user and deletes the active session. * Logs out the user and deletes the active session.
* *
* @api {post} /user/logout Logout a user
* @apiDescription This resource deletes the authentication token created by POST /user/login and removes the cookie.
* @apiName PostUserLogout
* @apiGroup User
* @apiSuccess {String} auth_token An expired cookie named auth_token containing no value
* @apiError (server) AuthenticationTokenError Error deleting the authentication token
* @apiPermission user
* @apiVersion 1.0.0
*
* @return Response * @return Response
*/ */
@POST @POST
@ -337,7 +404,7 @@ public class UserResource extends BaseResource {
try { try {
authenticationTokenDao.delete(authToken); authenticationTokenDao.delete(authToken);
} catch (Exception e) { } catch (Exception e) {
throw new ServerException("AuthenticationTokenError", "Error deleting authentication token: " + authToken, e); throw new ServerException("AuthenticationTokenError", "Error deleting the authentication token: " + authToken, e);
} }
// Deletes the client token in the HTTP response // Deletes the client token in the HTTP response
@ -347,8 +414,17 @@ public class UserResource extends BaseResource {
} }
/** /**
* Delete a user. * Deletes the current user.
* *
* @api {delete} /user Delete the current user
* @apiDescription All associated entities will be deleted as well.
* @apiName DeleteUser
* @apiGroup User
* @apiSuccess {String} status Status OK
* @apiError (client) ForbiddenError The admin user cannot be deleted
* @apiPermission user
* @apiVersion 1.0.0
*
* @return Response * @return Response
*/ */
@DELETE @DELETE
@ -396,7 +472,17 @@ public class UserResource extends BaseResource {
/** /**
* Deletes a user. * Deletes a user.
* *
* @api {delete} /user/:username Delete a user
* @apiDescription All associated entities will be deleted as well.
* @apiName DeleteUserUsername
* @apiGroup User
* @apiSuccess {String} status Status OK
* @apiError (client) UserNotFound The user does not exist
* @apiError (client) ForbiddenError The admin user cannot be deleted
* @apiPermission admin
* @apiVersion 1.0.0
*
* @param username Username * @param username Username
* @return Response * @return Response
*/ */
@ -412,7 +498,7 @@ public class UserResource extends BaseResource {
UserDao userDao = new UserDao(); UserDao userDao = new UserDao();
User user = userDao.getActiveByUsername(username); User user = userDao.getActiveByUsername(username);
if (user == null) { if (user == null) {
throw new ClientException("UserNotFound", "The user doesn't exist"); throw new ClientException("UserNotFound", "The user does not exist");
} }
// Ensure that the admin user is not deleted // Ensure that the admin user is not deleted
@ -455,7 +541,22 @@ public class UserResource extends BaseResource {
/** /**
* Returns the information about the connected user. * Returns the information about the connected user.
* *
* @api {get} /user Get the current user
* @apiName GetUser
* @apiGroup User
* @apiSuccess {Boolean} anonymous True if no user is connected
* @apiSuccess {Boolean} is_default_password True if the admin has the default password
* @apiSuccess {String} username Username
* @apiSuccess {String} email E-mail
* @apiSuccess {Number} storage_quota Storage quota (in bytes)
* @apiSuccess {Number} storage_current Quota used (in bytes)
* @apiSuccess {Boolean} totp_enabled True if TOTP authentication is enabled
* @apiSuccess {String[]} base_functions Base functions
* @apiSuccess {String[]} groups Groups
* @apiPermission none
* @apiVersion 1.0.0
*
* @return Response * @return Response
*/ */
@GET @GET
@ -513,7 +614,20 @@ public class UserResource extends BaseResource {
/** /**
* Returns the information about a user. * Returns the information about a user.
* *
* @api {get} /user/:username Get a user
* @apiName GetUserUsername
* @apiGroup User
* @apiParam {String} username Username
* @apiSuccess {String} username Username
* @apiSuccess {String} email E-mail
* @apiSuccess {Number} storage_quota Storage quota (in bytes)
* @apiSuccess {Number} storage_current Quota used (in bytes)
* @apiSuccess {String[]} groups Groups
* @apiError (client) UserNotFound The user does not exist
* @apiPermission user
* @apiVersion 1.0.0
*
* @param username Username * @param username Username
* @return Response * @return Response
*/ */
@ -528,7 +642,7 @@ public class UserResource extends BaseResource {
UserDao userDao = new UserDao(); UserDao userDao = new UserDao();
User user = userDao.getActiveByUsername(username); User user = userDao.getActiveByUsername(username);
if (user == null) { if (user == null) {
throw new ClientException("UserNotFound", "The user doesn't exist"); throw new ClientException("UserNotFound", "The user does not exist");
} }
// Groups // Groups
@ -552,7 +666,21 @@ public class UserResource extends BaseResource {
/** /**
* Returns all active users. * Returns all active users.
* *
* @api {get} /user/list Get users
* @apiName GetUserList
* @apiGroup User
* @apiParam {Number} sort_column Column index to sort on
* @apiSuccess {String[]} users List of users
* @apiSuccess {String} users.id ID
* @apiSuccess {String} users.username Username
* @apiSuccess {String} users.email E-mail
* @apiSuccess {Number} users.storage_quota Storage quota (in bytes)
* @apiSuccess {Number} users.storage_current Quota used (in bytes)
* @apiSuccess {Number} users.create_date Create date (timestamp)
* @apiPermission user
* @apiVersion 1.0.0
*
* @param sortColumn Sort index * @param sortColumn Sort index
* @param asc If true, ascending sorting, else descending * @param asc If true, ascending sorting, else descending
* @param groupName Only return users from this group * @param groupName Only return users from this group
@ -600,7 +728,20 @@ public class UserResource extends BaseResource {
/** /**
* Returns all active sessions. * Returns all active sessions.
* *
* @api {get} /user/session Get active sessions
* @apiDescription This resource lists all active token which can be used to log in to the current user account.
* @apiName GetUserSession
* @apiGroup User
* @apiSuccess {String[]} sessions List of sessions
* @apiSuccess {Number} create_date Create date of this token
* @apiSuccess {String} ip IP used to log in
* @apiSuccess {String} user_agent User agent used to log in
* @apiSuccess {Number} last_connection_date Last connection date (timestamp)
* @apiSuccess {Boolean} current If true, this token is the current one
* @apiPermission user
* @apiVersion 1.0.0
*
* @return Response * @return Response
*/ */
@GET @GET
@ -635,7 +776,15 @@ public class UserResource extends BaseResource {
/** /**
* Deletes all active sessions except the one used for this request. * Deletes all active sessions except the one used for this request.
* *
* @api {delete} /user/session Delete all sessions
* @apiDescription This resource deletes all active token linked to this account, except the one used to make this request.
* @apiName DeleteUserSession
* @apiGroup User
* @apiSuccess {String} status Status OK
* @apiPermission user
* @apiVersion 1.0.0
*
* @return Response * @return Response
*/ */
@DELETE @DELETE
@ -660,7 +809,16 @@ public class UserResource extends BaseResource {
/** /**
* Enable time-based one-time password. * Enable time-based one-time password.
* *
* @api {post} /user/enable_totp Enable TOTP authentication
* @apiDescription This resource enables the Time-based One-time Password authentication.
* All following login will need a validation code generated from the given secret seed.
* @apiName PostUserEnableTotp
* @apiGroup User
* @apiSuccess {String} secret Secret TOTP seed to initiate the algorithm
* @apiPermission user
* @apiVersion 1.0.0
*
* @return Response * @return Response
*/ */
@POST @POST
@ -687,7 +845,15 @@ public class UserResource extends BaseResource {
/** /**
* Disable time-based one-time password. * Disable time-based one-time password.
* *
* @api {post} /user/disable_totp Disable TOTP authentication
* @apiName PostUserDisableTotp
* @apiGroup User
* @apiParam {String{1..100}} password Password
* @apiSuccess {String} status Status OK
* @apiPermission user
* @apiVersion 1.0.0
*
* @param password Password * @param password Password
* @return Response * @return Response
*/ */
@ -720,7 +886,7 @@ public class UserResource extends BaseResource {
/** /**
* Returns the authentication token value. * Returns the authentication token value.
* *
* @return Token value * @return Token value
*/ */
private String getAuthToken() { private String getAuthToken() {

View File

@ -20,6 +20,24 @@ import java.util.List;
*/ */
@Path("/vocabulary") @Path("/vocabulary")
public class VocabularyResource extends BaseResource { public class VocabularyResource extends BaseResource {
/**
* Get a vocabulary.
*
* @api {get} /vocabulary/:name Get a vocabulary
* @apiName GetVocabularyName
* @apiGroup Vocabulary
* @apiParam {String} name Vocabulary name
* @apiSuccess {String[]} entries List of vocabulary entries
* @apiSuccess {String} entries.id ID
* @apiSuccess {String} entries.name Name
* @apiSuccess {String} entries.value Value
* @apiSuccess {Number} entries.order Order
* @apiPermission user
* @apiVersion 1.0.0
*
* @param name Name
* @return Response
*/
@GET @GET
@Path("{name: [a-z0-9\\-]+}") @Path("{name: [a-z0-9\\-]+}")
public Response get(@PathParam("name") String name) { public Response get(@PathParam("name") String name) {
@ -46,8 +64,21 @@ public class VocabularyResource extends BaseResource {
} }
/** /**
* Add a vocabulary. * Add a vocabulary entry.
* *
* @api {put} /vocabulary Add a vocabulary entry
* @apiName PutVocabulary
* @apiGroup Vocabulary
* @apiParam {String{1..50}} name Vocabulary name
* @apiParam {String{1..500}} value Entry value
* @apiParam {Number} order Entry order
* @apiSuccess {String} id ID
* @apiSuccess {String} name Name
* @apiSuccess {String} value Value
* @apiSuccess {Number} order Order
* @apiPermission admin
* @apiVersion 1.0.0
*
* @param name Name * @param name Name
* @param value Value * @param value Value
* @param orderStr Order * @param orderStr Order
@ -86,7 +117,21 @@ public class VocabularyResource extends BaseResource {
} }
/** /**
* Update a vocabulary. * Update a vocabulary entry.
*
* @api {post} /vocabulary/:id Update a vocabulary entry
* @apiName PostVocabularyId
* @apiGroup Vocabulary
* @apiParam {String} id Entry ID
* @apiParam {String{1..50}} name Vocabulary name
* @apiParam {String{1..500}} value Entry value
* @apiParam {Number} order Entry order
* @apiSuccess {String} id ID
* @apiSuccess {String} name Name
* @apiSuccess {String} value Value
* @apiSuccess {Number} order Order
* @apiPermission admin
* @apiVersion 1.0.0
* *
* @param id ID * @param id ID
* @param name Name * @param name Name
@ -145,8 +190,16 @@ public class VocabularyResource extends BaseResource {
} }
/** /**
* Delete a vocabulary. * Delete a vocabulary entry.
* *
* @api {delete} /vocabulary/:id Delete vocabulary entry
* @apiName DeleteVocabularyId
* @apiGroup Vocabulary
* @apiParam {String} id Entry ID
* @apiSuccess {String} status Status OK
* @apiPermission admin
* @apiVersion 1.0.0
*
* @param id ID * @param id ID
* @return Response * @return Response
*/ */

View File

@ -4,9 +4,8 @@ module.exports = function(grunt) {
grunt.initConfig({ grunt.initConfig({
pkg: grunt.file.readJSON('package.json'), pkg: grunt.file.readJSON('package.json'),
clean: { clean: {
dist: { init: ['dist'],
src: ['dist'] after: ['dist/style.css', 'dist/docs.js', 'dist/share.js', 'dist/less.css', 'dist/app']
}
}, },
ngmin: { ngmin: {
dist: { dist: {
@ -78,12 +77,6 @@ module.exports = function(grunt) {
dest: 'dist/share.html' dest: 'dist/share.html'
} }
}, },
remove: {
dist: {
fileList: ['dist/style.css', 'dist/docs.js', 'dist/share.js', 'dist/less.css'],
dirList: ['dist/app']
}
},
cleanempty: { cleanempty: {
options: { options: {
files: false, files: false,
@ -100,6 +93,12 @@ module.exports = function(grunt) {
to: grunt.option('apiurl') || '../api' to: grunt.option('apiurl') || '../api'
}] }]
} }
},
apidoc: {
generate: {
src: '../java/',
dest: 'dist/apidoc/'
}
} }
}); });
@ -111,12 +110,12 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-htmlrefs'); grunt.loadNpmTasks('grunt-htmlrefs');
grunt.loadNpmTasks('grunt-css'); grunt.loadNpmTasks('grunt-css');
grunt.loadNpmTasks('grunt-contrib-less'); grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-remove');
grunt.loadNpmTasks('grunt-ngmin'); grunt.loadNpmTasks('grunt-ngmin');
grunt.loadNpmTasks('grunt-text-replace'); grunt.loadNpmTasks('grunt-text-replace');
grunt.loadNpmTasks('grunt-apidoc');
// Default tasks. // Default tasks.
grunt.registerTask('default', ['clean', 'ngmin', 'concat:docs', 'concat:share', 'less', 'concat:css', 'cssmin', grunt.registerTask('default', ['clean:init', 'ngmin', 'concat:docs', 'concat:share', 'less', 'concat:css', 'cssmin',
'uglify:docs', 'uglify:share', 'copy', 'remove', 'cleanempty', 'htmlrefs:index', 'htmlrefs:share', 'replace']); 'uglify:docs', 'uglify:share', 'copy', 'clean:after', 'cleanempty', 'htmlrefs:index', 'htmlrefs:share', 'replace', 'apidoc']);
}; };

View File

@ -2,25 +2,34 @@
"name": "sismics-docs", "name": "sismics-docs",
"description": "Lightweight document management system", "description": "Lightweight document management system",
"readme": "See http://github.com/simics/docs for more informations.", "readme": "See http://github.com/simics/docs for more informations.",
"version": "0.0.1", "version": "1.5.0",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git://github.com/sismics/docs.git" "url": "git://github.com/sismics/docs.git"
}, },
"apidoc": {
"name": "Sismics Docs API",
"title": "Sismics Docs API",
"url": "/api",
"template": {
"withCompare": false,
"withGenerator": false
}
},
"devDependencies": { "devDependencies": {
"grunt": "~0.4.2", "grunt": "^1.0.1",
"grunt-contrib-uglify": "~0.3.2", "grunt-apidoc": "^0.11.0",
"grunt-contrib-concat": "~0.3.0", "grunt-cleanempty": "^1.0.4",
"grunt-contrib-copy": "~0.5.0", "grunt-contrib-clean": "^1.0.0",
"grunt-contrib-clean": "~0.5.0", "grunt-contrib-concat": "^1.0.1",
"grunt-cleanempty": "~0.2.0", "grunt-contrib-copy": "^1.0.0",
"grunt-htmlrefs": "~0.5.0", "grunt-contrib-less": "^1.3.0",
"grunt-css": "~0.5.4", "grunt-contrib-uglify": "^1.0.1",
"grunt-contrib-less": "~0.9.0", "grunt-css": "^0.5.4",
"grunt-remove": "~0.1.0", "grunt-htmlrefs": "^0.5.0",
"grunt-ngmin": "0.0.3", "grunt-ngmin": "0.0.3",
"grunt-text-replace": "~0.3.11", "grunt-text-replace": "^0.4.0",
"protractor": "~3.2.2", "protractor": "^3.3.0",
"selenium": "~2.20.0" "selenium": "^2.20.0"
} }
} }

View File

@ -51,6 +51,8 @@
<div class="text-muted text-right"> <div class="text-muted text-right">
<ul class="list-inline"> <ul class="list-inline">
<li>Crafted with <span class="glyphicon glyphicon-heart"></span> by <a href="https://www.sismics.com" target="_blank">Sismics</a></li>
<li><a href="apidoc/">API Documentation</a></li>
<li><strong>Version:</strong> {{ app.current_version }}</li> <li><strong>Version:</strong> {{ app.current_version }}</li>
<li><strong>Memory:</strong> {{ app.free_memory / 1000000 | number: 0 }}/{{ app.total_memory / 1000000 | number: 0 }} MB</li> <li><strong>Memory:</strong> {{ app.free_memory / 1000000 | number: 0 }}/{{ app.total_memory / 1000000 | number: 0 }} MB</li>
</ul> </ul>

View File

@ -27,7 +27,7 @@
<div class="col-sm-7"> <div class="col-sm-7">
<input name="email" type="email" id="inputEmail" required class="form-control" <input name="email" type="email" id="inputEmail" required class="form-control"
ng-minlength="3" ng-maxlength="50" placeholder="E-mail" ng-model="user.email"/> ng-minlength="1" ng-maxlength="100" placeholder="E-mail" ng-model="user.email"/>
</div> </div>
<div class="col-sm-3"> <div class="col-sm-3">