#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
*/
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.
*/

View File

@ -67,7 +67,21 @@ import com.sismics.util.totp.GoogleAuthenticatorKey;
public class UserResource extends BaseResource {
/**
* 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 password Password
* @param email E-Mail
@ -88,7 +102,7 @@ public class UserResource extends BaseResource {
username = ValidationUtil.validateLength(username, "username", 3, 50);
ValidationUtil.validateAlphanumeric(username, "username");
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");
ValidationUtil.validateEmail(email, "email");
@ -115,7 +129,7 @@ public class UserResource extends BaseResource {
if ("AlreadyExistingUsername".equals(e.getMessage())) {
throw new ServerException("AlreadyExistingUsername", "Login already used", e);
} 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 email E-Mail
* @return Response
@ -142,7 +165,7 @@ public class UserResource extends BaseResource {
// Validate the input data
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
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 password Password
* @param email E-Mail
@ -186,7 +221,7 @@ public class UserResource extends BaseResource {
// Validate the input data
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
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
* @return Response
*/
@ -244,7 +288,21 @@ public class UserResource extends BaseResource {
/**
* 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.
*
*
* @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 password Password
* @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.
*
*
* @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
*/
@POST
@ -337,7 +404,7 @@ public class UserResource extends BaseResource {
try {
authenticationTokenDao.delete(authToken);
} 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
@ -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
*/
@DELETE
@ -396,7 +472,17 @@ public class UserResource extends BaseResource {
/**
* 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
* @return Response
*/
@ -412,7 +498,7 @@ public class UserResource extends BaseResource {
UserDao userDao = new UserDao();
User user = userDao.getActiveByUsername(username);
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
@ -455,7 +541,22 @@ public class UserResource extends BaseResource {
/**
* 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
*/
@GET
@ -513,7 +614,20 @@ public class UserResource extends BaseResource {
/**
* 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
* @return Response
*/
@ -528,7 +642,7 @@ public class UserResource extends BaseResource {
UserDao userDao = new UserDao();
User user = userDao.getActiveByUsername(username);
if (user == null) {
throw new ClientException("UserNotFound", "The user doesn't exist");
throw new ClientException("UserNotFound", "The user does not exist");
}
// Groups
@ -552,7 +666,21 @@ public class UserResource extends BaseResource {
/**
* 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 asc If true, ascending sorting, else descending
* @param groupName Only return users from this group
@ -600,7 +728,20 @@ public class UserResource extends BaseResource {
/**
* 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
*/
@GET
@ -635,7 +776,15 @@ public class UserResource extends BaseResource {
/**
* 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
*/
@DELETE
@ -660,7 +809,16 @@ public class UserResource extends BaseResource {
/**
* 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
*/
@POST
@ -687,7 +845,15 @@ public class UserResource extends BaseResource {
/**
* 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
* @return Response
*/
@ -720,7 +886,7 @@ public class UserResource extends BaseResource {
/**
* Returns the authentication token value.
*
*
* @return Token value
*/
private String getAuthToken() {

View File

@ -20,6 +20,24 @@ import java.util.List;
*/
@Path("/vocabulary")
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
@Path("{name: [a-z0-9\\-]+}")
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 value Value
* @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 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
* @return Response
*/

View File

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

View File

@ -2,25 +2,34 @@
"name": "sismics-docs",
"description": "Lightweight document management system",
"readme": "See http://github.com/simics/docs for more informations.",
"version": "0.0.1",
"version": "1.5.0",
"repository": {
"type": "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": {
"grunt": "~0.4.2",
"grunt-contrib-uglify": "~0.3.2",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-copy": "~0.5.0",
"grunt-contrib-clean": "~0.5.0",
"grunt-cleanempty": "~0.2.0",
"grunt-htmlrefs": "~0.5.0",
"grunt-css": "~0.5.4",
"grunt-contrib-less": "~0.9.0",
"grunt-remove": "~0.1.0",
"grunt": "^1.0.1",
"grunt-apidoc": "^0.11.0",
"grunt-cleanempty": "^1.0.4",
"grunt-contrib-clean": "^1.0.0",
"grunt-contrib-concat": "^1.0.1",
"grunt-contrib-copy": "^1.0.0",
"grunt-contrib-less": "^1.3.0",
"grunt-contrib-uglify": "^1.0.1",
"grunt-css": "^0.5.4",
"grunt-htmlrefs": "^0.5.0",
"grunt-ngmin": "0.0.3",
"grunt-text-replace": "~0.3.11",
"protractor": "~3.2.2",
"selenium": "~2.20.0"
"grunt-text-replace": "^0.4.0",
"protractor": "^3.3.0",
"selenium": "^2.20.0"
}
}

View File

@ -51,6 +51,8 @@
<div class="text-muted text-right">
<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>Memory:</strong> {{ app.free_memory / 1000000 | number: 0 }}/{{ app.total_memory / 1000000 | number: 0 }} MB</li>
</ul>

View File

@ -27,7 +27,7 @@
<div class="col-sm-7">
<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 class="col-sm-3">