diff --git a/docs-android/app/build.gradle b/docs-android/app/build.gradle index b99a5b46..062f5655 100644 --- a/docs-android/app/build.gradle +++ b/docs-android/app/build.gradle @@ -3,7 +3,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.1.0-beta1' + classpath 'com.android.tools.build:gradle:2.1.0' } } apply plugin: 'com.android.application' diff --git a/docs-android/app/src/main/java/com/sismics/docs/activity/MainActivity.java b/docs-android/app/src/main/java/com/sismics/docs/activity/MainActivity.java index 0c9232cb..0da860a8 100644 --- a/docs-android/app/src/main/java/com/sismics/docs/activity/MainActivity.java +++ b/docs-android/app/src/main/java/com/sismics/docs/activity/MainActivity.java @@ -87,13 +87,13 @@ public class MainActivity extends AppCompatActivity { tagListView.setEmptyView(tagProgressView); JSONObject cacheTags = PreferenceUtil.getCachedJson(this, PreferenceUtil.PREF_CACHED_TAGS_JSON); if (cacheTags != null) { - tagListView.setAdapter(new TagListAdapter(cacheTags.optJSONArray("stats"))); + tagListView.setAdapter(new TagListAdapter(cacheTags.optJSONArray("tags"))); } - TagResource.stats(this, new HttpCallback() { + TagResource.list(this, new HttpCallback() { @Override public void onSuccess(JSONObject response) { PreferenceUtil.setCachedJson(MainActivity.this, PreferenceUtil.PREF_CACHED_TAGS_JSON, response); - tagListView.setAdapter(new TagListAdapter(response.optJSONArray("stats"))); + tagListView.setAdapter(new TagListAdapter(response.optJSONArray("tags"))); tagProgressView.setVisibility(View.GONE); tagListView.setEmptyView(tagEmptyView); } @@ -158,6 +158,7 @@ public class MainActivity extends AppCompatActivity { @Override public void onFinish() { // Force logout in all cases, so the user is not stuck in case of network error + PreferenceUtil.clearAuthToken(MainActivity.this); ApplicationContext.getInstance().setUserInfo(getApplicationContext(), null); startActivity(new Intent(MainActivity.this, LoginActivity.class)); finish(); diff --git a/docs-android/app/src/main/java/com/sismics/docs/adapter/TagListAdapter.java b/docs-android/app/src/main/java/com/sismics/docs/adapter/TagListAdapter.java index f921a804..213bd59d 100644 --- a/docs-android/app/src/main/java/com/sismics/docs/adapter/TagListAdapter.java +++ b/docs-android/app/src/main/java/com/sismics/docs/adapter/TagListAdapter.java @@ -46,7 +46,7 @@ public class TagListAdapter extends BaseAdapter { // Reorder tags by parent/child relation and compute depth int depth = 0; - initTags(tags, JSONObject.NULL.toString(), depth); + initTags(tags, "", depth); } /** @@ -60,11 +60,10 @@ public class TagListAdapter extends BaseAdapter { // Get all tags with this parent for (JSONObject tag : tags) { String tagParentId = tag.optString("parent"); - if (tagParentId.equals(parentId)) { + if (parentId.equals(tagParentId)) { TagItem tagItem = new TagItem(); tagItem.id = tag.optString("id"); tagItem.name = tag.optString("name"); - tagItem.count = tag.optInt("count"); tagItem.color = tag.optString("color"); tagItem.depth = depth; tagItemList.add(tagItem); @@ -99,8 +98,6 @@ public class TagListAdapter extends BaseAdapter { TagItem tagItem = getItem(position); TextView tagTextView = (TextView) view.findViewById(R.id.tagTextView); tagTextView.setText(tagItem.name); - TextView tagCountTextView = (TextView) view.findViewById(R.id.tagCountTextView); - tagCountTextView.setText(String.format(Locale.ENGLISH, "%d", tagItem.count)); // Label color filtering ImageView labelImageView = (ImageView) view.findViewById(R.id.labelImageView); @@ -125,7 +122,6 @@ public class TagListAdapter extends BaseAdapter { public static class TagItem { private String id; private String name; - private int count; private String color; private int depth; diff --git a/docs-android/app/src/main/java/com/sismics/docs/resource/TagResource.java b/docs-android/app/src/main/java/com/sismics/docs/resource/TagResource.java index 34539d14..f7c17ec4 100644 --- a/docs-android/app/src/main/java/com/sismics/docs/resource/TagResource.java +++ b/docs-android/app/src/main/java/com/sismics/docs/resource/TagResource.java @@ -16,14 +16,14 @@ import okhttp3.Request; */ public class TagResource extends BaseResource { /** - * GET /tag/stats. + * GET /tag/list. * * @param context Context * @param callback Callback */ - public static void stats(Context context, HttpCallback callback) { + public static void list(Context context, HttpCallback callback) { Request request = new Request.Builder() - .url(HttpUrl.parse(getApiUrl(context) + "/tag/stats")) + .url(HttpUrl.parse(getApiUrl(context) + "/tag/list")) .get() .build(); OkHttpUtil.buildClient(context) diff --git a/docs-android/app/src/main/java/com/sismics/docs/util/PreferenceUtil.java b/docs-android/app/src/main/java/com/sismics/docs/util/PreferenceUtil.java index da8537ea..5df8974d 100644 --- a/docs-android/app/src/main/java/com/sismics/docs/util/PreferenceUtil.java +++ b/docs-android/app/src/main/java/com/sismics/docs/util/PreferenceUtil.java @@ -126,6 +126,7 @@ public class PreferenceUtil { /** * Returns auth token cookie from shared preferences. * + * @param context Context * @return Auth token */ public static String getAuthToken(Context context) { @@ -140,6 +141,16 @@ public class PreferenceUtil { return null; } + /** + * Clear all auth tokens. + * + * @param context Context + */ + public static void clearAuthToken(Context context) { + PersistentCookieStore cookieStore = new PersistentCookieStore(context); + cookieStore.removeAll(); + } + /** * Returns cleaned server URL. * diff --git a/docs-android/app/src/main/res/layout/tag_list_item.xml b/docs-android/app/src/main/res/layout/tag_list_item.xml index 2724a7b7..f238f1fb 100644 --- a/docs-android/app/src/main/res/layout/tag_list_item.xml +++ b/docs-android/app/src/main/res/layout/tag_list_item.xml @@ -28,17 +28,5 @@ android:textColor="#212121" android:text="Appartement" android:textSize="14sp"/> - - \ No newline at end of file diff --git a/docs-core/pom.xml b/docs-core/pom.xml index 498aee4b..85e0267d 100644 --- a/docs-core/pom.xml +++ b/docs-core/pom.xml @@ -5,7 +5,7 @@ com.sismics.docs docs-parent - 1.4-SNAPSHOT + 1.5-SNAPSHOT .. diff --git a/docs-stress/pom.xml b/docs-stress/pom.xml index e6cb862b..0ea52568 100644 --- a/docs-stress/pom.xml +++ b/docs-stress/pom.xml @@ -5,7 +5,7 @@ com.sismics.docs docs-parent - 1.4-SNAPSHOT + 1.5-SNAPSHOT .. diff --git a/docs-web-common/pom.xml b/docs-web-common/pom.xml index 1a736939..5a7e8a30 100644 --- a/docs-web-common/pom.xml +++ b/docs-web-common/pom.xml @@ -5,7 +5,7 @@ com.sismics.docs docs-parent - 1.4-SNAPSHOT + 1.5-SNAPSHOT .. diff --git a/docs-web/pom.xml b/docs-web/pom.xml index a3cba6c6..b66010c1 100644 --- a/docs-web/pom.xml +++ b/docs-web/pom.xml @@ -5,7 +5,7 @@ com.sismics.docs docs-parent - 1.4-SNAPSHOT + 1.5-SNAPSHOT .. diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/AclResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/AclResource.java index 480b9a51..ea0c7141 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/AclResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/AclResource.java @@ -31,7 +31,24 @@ import java.util.List; public class AclResource extends BaseResource { /** * Add an ACL. - * + * + * @api {put} /acl Add an ACL + * @apiName PutAcl + * @apiGroup Acl + * @apiParam {String} source Source ID + * @apiParam {String="READ","WRITE"} perm Permission + * @apiParam {String} target Target ID + * @apiParam {String="USER","GROUP","SHARE"} type Target type + * @apiSuccess {String} id Acl ID + * @apiSuccess {String} perm Permission + * @apiSuccess {String} name Target name + * @apiSuccess {String="USER","GROUP","SHARE"} type Target type + * @apiError (client) ForbiddenError Access denied + * @apiError (client) ValidationError Validation error + * @apiError (client) InvalidTarget This target does not exist + * @apiPermission user + * @apiVersion 1.5.0 + * * @param sourceId Source ID * @param permStr Permission * @param targetName Target name @@ -110,6 +127,19 @@ public class AclResource extends BaseResource { /** * Deletes an ACL. + * + * @api {delete} /acl/:source/:perm/:target Delete an ACL + * @apiName DeleteAcl + * @apiGroup Acl + * @apiParam {String} source Source ID + * @apiParam {String="READ","WRITE"} perm Permission + * @apiParam {String} target Target ID + * @apiSuccess {String} status Status OK + * @apiError (client) ForbiddenError Access denied + * @apiError (client) ValidationError Validation error + * @apiError (client) AclError Cannot delete base ACL on a document or a tag + * @apiPermission user + * @apiVersion 1.5.0 * * @param sourceId Source ID * @param permStr Permission @@ -162,6 +192,19 @@ public class AclResource extends BaseResource { /** * Search possible ACL target. + * + * @api {get} /acl/target/search Search in ACL targets + * @apiName GetAclTargetSearch + * @apiGroup Acl + * @apiParam {String} search Search query + * @apiSuccess {Object[]} users List of users + * @apiSuccess {String} users.name Username + * @apiSuccess {Object[]} groups List of groups + * @apiSuccess {String} groups.name Group name + * @apiError (client) ForbiddenError Access denied + * @apiError (client) ValidationError Validation error + * @apiPermission user + * @apiVersion 1.5.0 * * @param search Search query * @return Response diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/AppResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/AppResource.java index b5426eb2..2b48cf0b 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/AppResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/AppResource.java @@ -63,8 +63,19 @@ public class AppResource extends BaseResource { private static final Logger log = LoggerFactory.getLogger(AppResource.class); /** - * Return the information about the application. - * + * Returns informations about the application. + * + * @api {get} /app Get application informations + * @apiName GetApp + * @apiGroup App + * @apiSuccess {String} current_version API current version + * @apiSuccess {String} min_version API minimum version + * @apiSuccess {String} total_memory Allocated JVM memory (in bytes) + * @apiSuccess {String} free_memory Free JVM memory (in bytes) + * @apiError (client) ForbiddenError Access denied + * @apiPermission user + * @apiVersion 1.5.0 + * * @return Response */ @GET @@ -88,7 +99,26 @@ public class AppResource extends BaseResource { /** * Retrieve the application logs. - * + * + * @api {get} /app/log Get application logs + * @apiName GetAppLog + * @apiGroup App + * @apiParam {String="FATAL","ERROR","WARN","INFO","DEBUG"} level Minimum log level + * @apiParam {String} tag Filter on this logger tag + * @apiParam {String} message Filter on this message + * @apiParam {Number} limit Total number of logs to return + * @apiParam {Number} offset Start at this index + * @apiSuccess {String} total Total number of logs + * @apiSuccess {Object[]} logs List of logs + * @apiSuccess {String} logs.date Date + * @apiSuccess {String} logs.level Level + * @apiSuccess {String} logs.tag Tag + * @apiSuccess {String} logs.message Message + * @apiError (client) ForbiddenError Access denied + * @apiError (server) ServerError MEMORY appender not configured + * @apiPermission user + * @apiVersion 1.5.0 + * * @param minLevel Filter on logging level * @param tag Filter on logger name / tag * @param message Filter on message @@ -107,6 +137,7 @@ public class AppResource extends BaseResource { if (!authenticate()) { throw new ForbiddenClientException(); } + // Get the memory appender org.apache.log4j.Logger logger = org.apache.log4j.Logger.getRootLogger(); Appender appender = logger.getAppender("MEMORY"); @@ -141,7 +172,16 @@ public class AppResource extends BaseResource { /** * Destroy and rebuild Lucene index. - * + * + * @api {post} /app/batch/reindex Rebuild the search index + * @apiName PostAppBatchReindex + * @apiGroup App + * @apiSuccess {String} status Status OK + * @apiError (client) ForbiddenError Access denied + * @apiError (server) IndexingError Error rebuilding the index + * @apiPermission admin + * @apiVersion 1.5.0 + * * @return Response */ @POST @@ -155,7 +195,7 @@ public class AppResource extends BaseResource { try { AppContext.getInstance().getIndexingService().rebuildIndex(); } catch (Exception e) { - throw new ServerException("IndexingError", "Error rebuilding index", e); + throw new ServerException("IndexingError", "Error rebuilding the index", e); } // Always return OK @@ -166,7 +206,16 @@ public class AppResource extends BaseResource { /** * Clean storage. - * + * + * @api {post} /app/batch/clean_storage Clean the file and DB storage + * @apiName PostAppBatchCleanStorage + * @apiGroup App + * @apiSuccess {String} status Status OK + * @apiError (client) ForbiddenError Access denied + * @apiError (server) FileError Error deleting orphan files + * @apiPermission admin + * @apiVersion 1.5.0 + * * @return Response */ @POST @@ -275,7 +324,16 @@ public class AppResource extends BaseResource { /** * Recompute the quota for each user. - * + * + * @api {post} /app/batch/recompute_quote Recompute user quotas + * @apiName PostAppBatchRecomputeQuota + * @apiGroup App + * @apiSuccess {String} status Status OK + * @apiError (client) ForbiddenError Access denied + * @apiError (server) MissingFile File does not exist + * @apiPermission admin + * @apiVersion 1.5.0 + * * @return Response */ @POST @@ -327,6 +385,16 @@ public class AppResource extends BaseResource { /** * Add base ACLs to tags. * + * @api {post} /app/batch/recompute_quote Add base ACL to tags + * @apiDescription This resource must be used after migrating to 1.5. + * It will not do anything if base ACL are already present on tags. + * @apiName PostAppBatchTagAcls + * @apiGroup App + * @apiSuccess {String} status Status OK + * @apiError (client) ForbiddenError Access denied + * @apiPermission admin + * @apiVersion 1.5.0 + * * @return Response */ @POST diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/AuditLogResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/AuditLogResource.java index 83f5b798..91eeb8e9 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/AuditLogResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/AuditLogResource.java @@ -30,7 +30,26 @@ import javax.ws.rs.core.Response; public class AuditLogResource extends BaseResource { /** * Returns the list of all logs for a document or user. - * + * + * @api {get} /auditlog Get audit logs + * @apiDescription If no document ID is provided, logs for the current user will be returned. + * @apiName GetAuditlog + * @apiGroup Auditlog + * @apiParam {String} [document] Document ID + * @apiSuccess {String} total Total number of logs + * @apiSuccess {Object[]} logs List of logs + * @apiSuccess {String} logs.id ID + * @apiSuccess {String} logs.username Username + * @apiSuccess {String} logs.target Entity ID + * @apiSuccess {String="Acl","Comment","Document","File","Group","Tag","User"} logs.class Entity type + * @apiSuccess {String="CREATE","UPDATE","DELETE"} logs.type Type + * @apiSuccess {String} logs.message Message + * @apiSuccess {Number} logs.create_date Create date (timestamp) + * @apiError (client) ForbiddenError Access denied + * @apiError (client) NotFound Document not found + * @apiPermission user + * @apiVersion 1.5.0 + * * @return Response */ @GET diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/BaseResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/BaseResource.java index ad3fe187..f05d6d56 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/BaseResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/BaseResource.java @@ -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. */ diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/CommentResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/CommentResource.java index ce745054..49a88fec 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/CommentResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/CommentResource.java @@ -25,6 +25,22 @@ import java.util.List; public class CommentResource extends BaseResource { /** * Add a comment. + * + * @api {put} /comment Add a comment + * @apiName PutComment + * @apiGroup Comment + * @apiParam {String} id Document ID + * @apiParam {String} content Comment content + * @apiSuccess {String} id Comment ID + * @apiSuccess {String} content Content + * @apiSuccess {String} creator Username + * @apiSuccess {String} creator_gravatar Creator Gravatar hash + * @apiSuccess {Number} create_date Create date (timestamp) + * @apiError (client) ForbiddenError Access denied + * @apiError (client) ValidationError Validation error + * @apiError (client) NotFound Document not found + * @apiPermission user + * @apiVersion 1.5.0 * * @param documentId Document ID * @param content Comment content @@ -67,7 +83,17 @@ public class CommentResource extends BaseResource { /** * Delete a comment. - * + * + * @api {delete} /comment/:id Delete a comment + * @apiName DeleteComment + * @apiGroup Comment + * @apiParam {String} id Comment ID + * @apiSuccess {String} status Status OK + * @apiError (client) ForbiddenError Access denied + * @apiError (client) NotFound Comment or document not found + * @apiPermission user + * @apiVersion 1.5.0 + * * @param id Comment ID * @return Response */ @@ -105,7 +131,22 @@ public class CommentResource extends BaseResource { /** * Get all comments on a document. - * + * + * @api {get} /comment/:id Get comments + * @apiName GetComment + * @apiGroup Comment + * @apiParam {String} id Document ID + * @apiParam {String} share Share ID + * @apiSuccess {Object[]} comments List of comments + * @apiSuccess {String} comments.id Comment ID + * @apiSuccess {String} comments.content Content + * @apiSuccess {String} comments.creator Username + * @apiSuccess {String} comments.creator_gravatar Creator Gravatar hash + * @apiSuccess {Number} comments.create_date Create date (timestamp) + * @apiError (client) NotFound Document not found + * @apiPermission none + * @apiVersion 1.5.0 + * * @param documentId DocumentID * @return Response */ diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java index 1f7bccbc..918725fa 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java @@ -56,7 +56,56 @@ import java.util.*; public class DocumentResource extends BaseResource { /** * Returns a document. - * + * + * @api {get} /document/:id Get a document + * @apiName GetDocument + * @apiGroup Document + * @apiParam {String} id Document ID + * @apiParam {String} share Share ID + * @apiSuccess {String} id ID + * @apiSuccess {String} title Title + * @apiSuccess {String} description Description + * @apiSuccess {Number} create_date Create date (timestamp) + * @apiSuccess {String="eng","fra","jpn"} language Language + * @apiSuccess {Boolean} shared True if the document is shared + * @apiSuccess {Number} file_count Number of files in this document + * @apiSuccess {Object[]} tags List of tags + * @apiSuccess {String} tags.id ID + * @apiSuccess {String} tags.name Name + * @apiSuccess {String} tags.color Color + * @apiSuccess {String} subject Subject + * @apiSuccess {String} identifier Identifier + * @apiSuccess {String} publisher Publisher + * @apiSuccess {String} format Format + * @apiSuccess {String} source Source + * @apiSuccess {String} type Type + * @apiSuccess {String} coverage Coverage + * @apiSuccess {String} rights Rights + * @apiSuccess {String} creator Username of the creator + * @apiSuccess {Boolean} writable True if the document is writable by the current user + * @apiSuccess {Object[]} acls List of ACL + * @apiSuccess {String} acls.id ID + * @apiSuccess {String="READ","WRITE"} acls.perm Permission + * @apiSuccess {String} acls.name Target name + * @apiSuccess {String="USER","GROUP","SHARE"} acls.type Target type + * @apiSuccess {Object[]} inherited_acls List of ACL not directly applied to this document + * @apiSuccess {String="READ","WRITE"} inherited_acls.perm Permission + * @apiSuccess {String} inherited_acls.source_id Source ID + * @apiSuccess {String} inherited_acls.source_name Source name + * @apiSuccess {String} inherited_acls.id ID + * @apiSuccess {String} inherited_acls.name Target name + * @apiSuccess {String="USER","GROUP","SHARE"} inherited_acls.type Target type + * @apiSuccess {Object[]} contributors List of users having contributed to this document + * @apiSuccess {String} contributors.username Username + * @apiSuccess {String} contributors.email E-mail + * @apiSuccess {Object[]} relations List of document related to this one + * @apiSuccess {String} relations.id ID + * @apiSuccess {String} relations.title Title + * @apiSuccess {String} relations.source True if this document is the source of the relation + * @apiError (client) NotFound Document not found + * @apiPermission none + * @apiVersion 1.5.0 + * * @param documentId Document ID * @param shareId Share ID * @return Response @@ -166,7 +215,22 @@ public class DocumentResource extends BaseResource { /** * Export a document to PDF. - * + * + * @api {get} /document/:id/pdf Export a document to PDF + * @apiName GetDocumentPdf + * @apiGroup Document + * @apiParam {String} id Document ID + * @apiParam {String} share Share ID + * @apiParam {Boolean} metadata If true, export metadata + * @apiParam {Boolean} comments If true, export comments + * @apiParam {Boolean} fitimagetopage If true, fit the images to pages + * @apiParam {Number} margin Margin around the pages, in millimeter + * @apiSuccess {String} pdf The whole response is the PDF file + * @apiError (client) NotFound Document not found + * @apiError (client) ValidationError Validation error + * @apiPermission none + * @apiVersion 1.5.0 + * * @param documentId Document ID * @param shareId Share ID * @param metadata Export metadata @@ -233,7 +297,33 @@ public class DocumentResource extends BaseResource { /** * Returns all documents. - * + * + * @api {get} /document/list Get documents + * @apiName GetDocumentList + * @apiGroup Document + * @apiParam {String} limit Total number of documents to return + * @apiParam {String} offset Start at this index + * @apiParam {Number} sort_column Column index to sort on + * @apiParam {Boolean} asc If true, sort in ascending order + * @apiParam {String} search Search query + * @apiSuccess {Number} total Total number of documents + * @apiSuccess {Object[]} documents List of documents + * @apiSuccess {String} documents.id ID + * @apiSuccess {String} documents.title Title + * @apiSuccess {String} documents.description Description + * @apiSuccess {Number} documents.create_date Create date (timestamp) + * @apiSuccess {String="eng","fra","jpn"} documents.language Language + * @apiSuccess {Boolean} documents.shared True if the document is shared + * @apiSuccess {Number} documents.file_count Number of files in this document + * @apiSuccess {Object[]} documents.tags List of tags + * @apiSuccess {String} documents.tags.id ID + * @apiSuccess {String} documents.tags.name Name + * @apiSuccess {String} documents.tags.color Color + * @apiError (client) ForbiddenError Access denied + * @apiError (server) SearchError Error searching in documents + * @apiPermission user + * @apiVersion 1.5.0 + * * @param limit Page limit * @param offset Page offset * @param sortColumn Sort column @@ -422,7 +512,30 @@ public class DocumentResource extends BaseResource { /** * Creates a new document. - * + * + * @api {put} /document Add a document + * @apiName PutDocument + * @apiGroup Document + * @apiParam {String} title Title + * @apiParam {String} [description] Description + * @apiParam {String} [subject] Subject + * @apiParam {String} [identifier] Identifier + * @apiParam {String} [publisher] Publisher + * @apiParam {String} [format] Format + * @apiParam {String} [source] Source + * @apiParam {String} [type] Type + * @apiParam {String} [coverage] Coverage + * @apiParam {String} [rights] Rights + * @apiParam {String[]} [tags] List of tags ID + * @apiParam {String[]} [relations] List of related documents ID + * @apiParam {String="eng","fra","jpn"} language Language + * @apiParam {Number} [create_date] Create date (timestamp) + * @apiSuccess {String} id Document ID + * @apiError (client) ForbiddenError Access denied + * @apiError (client) ValidationError Validation error + * @apiPermission user + * @apiVersion 1.5.0 + * * @param title Title * @param description Description * @param subject Subject @@ -532,7 +645,32 @@ public class DocumentResource extends BaseResource { /** * Updates the document. - * + * + * @api {post} /document/:id Update a document + * @apiName PostDocument + * @apiGroup Document + * @apiParam {String} id ID + * @apiParam {String} title Title + * @apiParam {String} [description] Description + * @apiParam {String} [subject] Subject + * @apiParam {String} [identifier] Identifier + * @apiParam {String} [publisher] Publisher + * @apiParam {String} [format] Format + * @apiParam {String} [source] Source + * @apiParam {String} [type] Type + * @apiParam {String} [coverage] Coverage + * @apiParam {String} [rights] Rights + * @apiParam {String[]} [tags] List of tags ID + * @apiParam {String[]} [relations] List of related documents ID + * @apiParam {String="eng","fra","jpn"} language Language + * @apiParam {Number} [create_date] Create date (timestamp) + * @apiSuccess {String} id Document ID + * @apiError (client) ForbiddenError Access denied or document not writable + * @apiError (client) ValidationError Validation error + * @apiError (client) NotFound Document not found + * @apiPermission user + * @apiVersion 1.5.0 + * * @param title Title * @param description Description * @return Response @@ -675,7 +813,17 @@ public class DocumentResource extends BaseResource { /** * Deletes a document. - * + * + * @api {delete} /document/:id Delete a document + * @apiName DeleteDocument + * @apiGroup Document + * @apiParam {String} id ID + * @apiSuccess {String} status Status OK + * @apiError (client) ForbiddenError Access denied + * @apiError (client) NotFound Document not found + * @apiPermission user + * @apiVersion 1.5.0 + * * @param id Document ID * @return Response */ diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/FileResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/FileResource.java index 35520179..cd4e9b46 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/FileResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/FileResource.java @@ -61,7 +61,28 @@ import com.sismics.util.mime.MimeTypeUtil; public class FileResource extends BaseResource { /** * Add a file (with or without a document). - * + * + * @api {put} /file Add a file + * @apiDescription A file can be added without associated document, and will go in a temporary storage waiting for one. + * This resource accepts only multipart/form-data. + * @apiName PutFile + * @apiGroup File + * @apiParam {String} id Document ID + * @apiParam {String} file File data + * @apiSuccess {String} status Status OK + * @apiSuccess {String} id File ID + * @apiSuccess {Number} size File size (in bytes) + * @apiError (client) ForbiddenError Access denied + * @apiError (client) ValidationError Validation error + * @apiError (client) NotFound Document not found + * @apiError (server) StreamError Error reading the input file + * @apiError (server) ErrorGuessMime Error guessing mime type + * @apiError (client) InvalidFileType File type not recognized + * @apiError (client) QuotaReached Quota limit reached + * @apiError (server) FileError Error adding a file + * @apiPermission user + * @apiVersion 1.5.0 + * * @param documentId Document ID * @param fileBodyPart File to add * @return Response @@ -179,7 +200,20 @@ public class FileResource extends BaseResource { /** * Attach a file to a document. - * + * + * @api {post} /file/:fileId Attach a file to a document + * @apiName PostFile + * @apiGroup File + * @apiParam {String} fileId File ID + * @apiParam {String} id Document ID + * @apiSuccess {String} status Status OK + * @apiError (client) ForbiddenError Access denied + * @apiError (client) ValidationError Validation error + * @apiError (client) IllegalFile File not orphan + * @apiError (server) AttachError Error attaching file to document + * @apiPermission user + * @apiVersion 1.5.0 + * * @param id File ID * @return Response */ @@ -235,7 +269,7 @@ public class FileResource extends BaseResource { documentUpdatedAsyncEvent.setDocumentId(documentId); AppContext.getInstance().getAsyncEventBus().post(documentUpdatedAsyncEvent); } catch (Exception e) { - throw new ClientException("AttachError", "Error attaching file to document", e); + throw new ServerException("AttachError", "Error attaching file to document", e); } // Always return OK @@ -246,7 +280,19 @@ public class FileResource extends BaseResource { /** * Reorder files. - * + * + * @api {post} /file/:reorder Reorder files + * @apiName PostFileReorder + * @apiGroup File + * @apiParam {String} id Document ID + * @apiParam {String[]} order List of files ID + * @apiSuccess {String} status Status OK + * @apiError (client) ForbiddenError Access denied + * @apiError (client) ValidationError Validation error + * @apiError (client) NotFound Document not found + * @apiPermission user + * @apiVersion 1.5.0 + * * @param documentId Document ID * @param idList List of files ID in the new order * @return Response @@ -287,7 +333,24 @@ public class FileResource extends BaseResource { /** * Returns files linked to a document or not linked to any document. - * + * + * @api {post} /file/list Get files + * @apiName GetFileList + * @apiGroup File + * @apiParam {String} id Document ID + * @apiParam {String} share Share ID + * @apiSuccess {Object[]} files List of files + * @apiSuccess {String} files.id ID + * @apiSuccess {String} files.mimetype MIME type + * @apiSuccess {String} files.document_id Document ID + * @apiSuccess {String} files.create_date Create date (timestamp) + * @apiSuccess {String} files.size File size (in bytes) + * @apiError (client) ForbiddenError Access denied + * @apiError (client) NotFound Document not found + * @apiError (server) FileError Unable to get the size of a file + * @apiPermission none + * @apiVersion 1.5.0 + * * @param documentId Document ID * @param shareId Sharing ID * @return Response @@ -333,7 +396,18 @@ public class FileResource extends BaseResource { /** * Deletes a file. - * + * + * @api {delete} /file/:id Delete a file + * @apiName DeleteFile + * @apiGroup File + * @apiParam {String} id File ID + * @apiParam {String} share Share ID + * @apiSuccess {String} status Status OK + * @apiError (client) ForbiddenError Access denied + * @apiError (client) NotFound File or document not found + * @apiPermission user + * @apiVersion 1.5.0 + * * @param id File ID * @return Response */ @@ -399,7 +473,21 @@ public class FileResource extends BaseResource { /** * Returns a file. - * + * + * @api {delete} /file/:id/data Get a file data + * @apiName GetFile + * @apiGroup File + * @apiParam {String} id File ID + * @apiParam {String} share Share ID + * @apiParam {String="web","thumb"} [size] Size variation + * @apiSuccess {Object} file The file data is the whole response + * @apiError (client) SizeError Size must be web or thumb + * @apiError (client) ForbiddenError Access denied or document not visible + * @apiError (client) NotFound File not found + * @apiError (server) ServiceUnavailable Error reading the file + * @apiPermission none + * @apiVersion 1.5.0 + * * @param fileId File ID * @return Response */ @@ -498,7 +586,18 @@ public class FileResource extends BaseResource { /** * Returns all files from a document, zipped. - * + * + * @api {get} /file/zip Get zipped files + * @apiName GetFileZip + * @apiGroup File + * @apiParam {String} id Document ID + * @apiParam {String} share Share ID + * @apiSuccess {Object} file The ZIP file is the whole response + * @apiError (client) NotFound Document not found + * @apiError (server) InternalServerError Error creating the ZIP file + * @apiPermission none + * @apiVersion 1.5.0 + * * @param documentId Document ID * @return Response */ @@ -542,7 +641,6 @@ public class FileResource extends BaseResource { ByteStreams.copy(decryptedStream, zipOutputStream); zipOutputStream.closeEntry(); } catch (Exception e) { - e.printStackTrace(); throw new WebApplicationException(e); } index++; diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/GroupResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/GroupResource.java index d345ee97..13d6915f 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/GroupResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/GroupResource.java @@ -34,7 +34,20 @@ import java.util.List; public class GroupResource extends BaseResource { /** * Add a group. - * + * + * @api {put} /group Add a group + * @apiName PutGroup + * @apiGroup Group + * @apiParam {String} name Group name + * @apiParam {String} [parent] Parent group name + * @apiSuccess {String} status Status OK + * @apiError (client) ForbiddenError Access denied + * @apiError (client) ValidationError Validation error + * @apiError (client) GroupAlreadyExists This group already exists + * @apiError (client) ParentGroupNotFound Parent group not found + * @apiPermission admin + * @apiVersion 1.5.0 + * * @return Response */ @PUT @@ -79,7 +92,21 @@ public class GroupResource extends BaseResource { /** * Update a group. - * + * + * @api {post} /group/:name Update a group + * @apiName PostGroup + * @apiGroup Group + * @apiParam {String} name Group name + * @apiParam {String} [parent] Parent group name + * @apiSuccess {String} status Status OK + * @apiError (client) ForbiddenError Access denied + * @apiError (client) ValidationError Validation error + * @apiError (client) GroupAlreadyExists This group already exists + * @apiError (client) ParentGroupNotFound Parent group not found + * @apiError (client) NotFound Group not found + * @apiPermission admin + * @apiVersion 1.5.0 + * * @return Response */ @POST @@ -131,7 +158,17 @@ public class GroupResource extends BaseResource { /** * Delete a group. - * + * + * @api {delete} /group/:name Delete a group + * @apiName DeleteGroup + * @apiGroup Group + * @apiParam {String} name Group name + * @apiSuccess {String} status Status OK + * @apiError (client) ForbiddenError Access denied + * @apiError (client) NotFound Group not found + * @apiPermission admin + * @apiVersion 1.5.0 + * * @return Response */ @DELETE @@ -160,7 +197,19 @@ public class GroupResource extends BaseResource { /** * Add a user to a group. - * + * + * @api {put} /group/:name Add a user to a group + * @apiName PutGroupMember + * @apiGroup Group + * @apiParam {String} name Group name + * @apiParam {String} username Username + * @apiSuccess {String} status Status OK + * @apiError (client) ForbiddenError Access denied + * @apiError (client) ValidationError Validation error + * @apiError (client) NotFound Group or user not found + * @apiPermission admin + * @apiVersion 1.5.0 + * * @param groupName Group name * @param username Username * @return Response @@ -217,7 +266,19 @@ public class GroupResource extends BaseResource { /** * Remove an user from a group. - * + * + * @api {delete} /group/:name/:username Remove a user from a group + * @apiName DeleteGroupMember + * @apiGroup Group + * @apiParam {String} name Group name + * @apiParam {String} username Username + * @apiSuccess {String} status Status OK + * @apiError (client) ForbiddenError Access denied + * @apiError (client) ValidationError Validation error + * @apiError (client) NotFound Group or user not found + * @apiPermission admin + * @apiVersion 1.5.0 + * * @param groupName Group name * @param username Username * @return Response @@ -260,7 +321,19 @@ public class GroupResource extends BaseResource { /** * Returns all active groups. - * + * + * @api {get} /group Get groups + * @apiName GetGroupList + * @apiGroup Group + * @apiParam {Number} sort_column Column index to sort on + * @apiParam {Boolean} asc If true, sort in ascending order + * @apiSuccess {Object[]} groups List of groups + * @apiSuccess {String} groups.name Name + * @apiSuccess {String} groups.parent Parent name + * @apiError (client) ForbiddenError Access denied + * @apiPermission user + * @apiVersion 1.5.0 + * * @param sortColumn Sort index * @param asc If true, ascending sorting, else descending * @return Response @@ -291,7 +364,19 @@ public class GroupResource extends BaseResource { /** * Get a group. - * + * + * @api {get} /group/:name Get a group + * @apiName GetGroup + * @apiGroup Group + * @apiParam {String} name Group name + * @apiSuccess {String} name Group name + * @apiSuccess {String} parent Parent name + * @apiSuccess {String[]} members List of members + * @apiError (client) ForbiddenError Access denied + * @apiError (client) NotFound Group not found + * @apiPermission user + * @apiVersion 1.5.0 + * * @param groupName Group name * @return Response */ diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/ShareResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/ShareResource.java index 9e4d49e5..28d9eb7c 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/ShareResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/ShareResource.java @@ -29,6 +29,21 @@ public class ShareResource extends BaseResource { /** * Add a share to a document. * + * @api {put} /share Share a document + * @apiName PutShare + * @apiGroup Share + * @apiParam {String} id Document ID + * @apiParam {String} name Share name + * @apiSuccess {String} id Acl ID + * @apiSuccess {String="READ","WRITE"} perm Permission + * @apiSuccess {String} name Share name + * @apiSuccess {String="SHARE"} type ACL type (always SHARE) + * @apiError (client) ForbiddenError Access denied + * @apiError (client) ValidationError Validation error + * @apiError (client) NotFound Share not found + * @apiPermission user + * @apiVersion 1.5.0 + * * @param documentId Document ID * @param name Share name * @return Response @@ -76,6 +91,17 @@ public class ShareResource extends BaseResource { /** * Deletes a share. * + * @api {delete} /share/:id Unshare a document + * @apiName DeleteShare + * @apiGroup Share + * @apiParam {String} id Acl ID + * @apiSuccess {String} status Status OK + * @apiError (client) ForbiddenError Access denied + * @apiError (client) ShareNotFound Share not found + * @apiError (client) DocumentNotFound Document not found + * @apiPermission user + * @apiVersion 1.5.0 + * * @param id Share ID * @return Response */ diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/TagResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/TagResource.java index 9e8f5871..452c2268 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/TagResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/TagResource.java @@ -33,7 +33,19 @@ import java.util.Set; public class TagResource extends BaseResource { /** * Returns the list of all visible tags. - * + * + * @api {get} /tag/list Get tags + * @apiName GetTagList + * @apiGroup Tag + * @apiSuccess {Object[]} tags List of tags + * @apiSuccess {String} tags.id ID + * @apiSuccess {String} tags.name Name + * @apiSuccess {String} tags.color Color + * @apiSuccess {String} tags.parent Parent + * @apiError (client) ForbiddenError Access denied + * @apiPermission user + * @apiVersion 1.5.0 + * * @return Response */ @GET @@ -73,6 +85,25 @@ public class TagResource extends BaseResource { /** * Returns a tag. * + * @api {get} /tag/:id Get a tag + * @apiName GetTag + * @apiGroup Tag + * @apiSuccess {String} id ID + * @apiSuccess {String} name Name + * @apiSuccess {String} creator Username of the creator + * @apiSuccess {String} color Color + * @apiSuccess {String} parent Parent + * @apiSuccess {Boolean} writable True if the tag is writable by the current user + * @apiSuccess {Object[]} acls List of ACL + * @apiSuccess {String} acls.id ID + * @apiSuccess {String="READ","WRITE"} acls.perm Permission + * @apiSuccess {String} acls.name Target name + * @apiSuccess {String="USER","GROUP","SHARE"} acls.type Target type + * @apiError (client) ForbiddenError Access denied + * @apiError (client) NotFound Tag not found + * @apiPermission user + * @apiVersion 1.5.0 + * * @param id Tag ID * @return Response */ @@ -113,7 +144,21 @@ public class TagResource extends BaseResource { /** * Creates a new tag. - * + * + * @api {put} /tag Create a tag + * @apiName PutTag + * @apiGroup Tag + * @apiParam {String} name Name + * @apiParam {String} color Color + * @apiParam {String} parent Parent ID + * @apiSuccess {String} id Tag ID + * @apiError (client) ForbiddenError Access denied + * @apiError (client) ValidationError Validation error + * @apiError (client) SpacesNotAllowed Spaces are not allowed in tag name + * @apiError (client) ParentNotFound Parent not found + * @apiPermission user + * @apiVersion 1.5.0 + * * @param name Name * @param color Color * @param parentId Parent ID @@ -178,7 +223,23 @@ public class TagResource extends BaseResource { /** * Update a tag. - * + * + * @api {post} /tag/:id Update a tag + * @apiName PostTag + * @apiGroup Tag + * @apiParam {String} id Tag ID + * @apiParam {String} name Name + * @apiParam {String} color Color + * @apiParam {String} parent Parent ID + * @apiSuccess {String} id Tag ID + * @apiError (client) ForbiddenError Access denied + * @apiError (client) ValidationError Validation error + * @apiError (client) SpacesNotAllowed Spaces are not allowed in tag name + * @apiError (client) ParentNotFound Parent not found + * @apiError (client) NotFound Tag not found + * @apiPermission user + * @apiVersion 1.5.0 + * * @param name Name * @param color Color * @param parentId Parent ID @@ -240,6 +301,16 @@ public class TagResource extends BaseResource { /** * Delete a tag. + * + * @api {delete} /tag/:id Delete a tag + * @apiName DeleteTag + * @apiGroup Tag + * @apiParam {String} id Tag ID + * @apiSuccess {String} status Status OK + * @apiError (client) ForbiddenError Access denied + * @apiError (client) NotFound Tag not found + * @apiPermission user + * @apiVersion 1.5.0 * * @param id Tag ID * @return Response diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/ThemeResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/ThemeResource.java index 46032995..dbd7bd15 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/ThemeResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/ThemeResource.java @@ -39,7 +39,14 @@ import java.util.Map; public class ThemeResource extends BaseResource { /** * Returns custom CSS stylesheet. - * + * + * @api {get} /theme/stylesheet Get the CSS stylesheet + * @apiName GetThemeStylesheet + * @apiGroup Theme + * @apiSuccess {String} stylesheet The whole response is the stylesheet + * @apiPermission none + * @apiVersion 1.5.0 + * * @return Response */ @GET @@ -60,6 +67,15 @@ public class ThemeResource extends BaseResource { /** * Returns the theme configuration. * + * @api {get} /theme Get the theme configuration + * @apiName GetTheme + * @apiGroup Theme + * @apiSuccess {String} name Application name + * @apiSuccess {String} color Main color + * @apiSuccess {String} css Custom CSS + * @apiPermission none + * @apiVersion 1.5.0 + * * @return Response */ @GET @@ -75,6 +91,18 @@ public class ThemeResource extends BaseResource { /** * Change the theme configuration. * + * @api {post} /theme Change the theme configuration + * @apiName PostTheme + * @apiGroup Theme + * @apiParam {String} name Application name + * @apiParam {String} color Main color + * @apiParam {String} css Custom CSS + * @apiSuccess {String} status Status OK + * @apiError (client) ForbiddenError Access denied + * @apiError (client) ValidationError Validation error + * @apiPermission admin + * @apiVersion 1.5.0 + * * @param color Theme color * @param name Application name * @param css Custom CSS @@ -117,6 +145,26 @@ public class ThemeResource extends BaseResource { return Response.ok().entity(response.build()).build(); } + /** + * Change a theme image. + * + * @api {put} /theme/image/:type Change a theme image + * @apiDescription This resource accepts only multipart/form-data. + * @apiName PutThemeImage + * @apiGroup Theme + * @apiParam {String="logo","background"} type Image type + * @apiParam {String} image Image data + * @apiSuccess {String} status Status OK + * @apiError (client) ForbiddenError Access denied + * @apiError (client) NoImageProvided An image is required + * @apiError (server) CopyError Error copying the image to the theme directory + * @apiPermission admin + * @apiVersion 1.5.0 + * + * @param type Image type + * @param imageBodyPart Image data + * @return Response + */ @PUT @Path("image/{type: logo|background}") @Consumes("multipart/form-data") @@ -143,6 +191,20 @@ public class ThemeResource extends BaseResource { return Response.ok().build(); } + /** + * Get theme images. + * + * @api {get} /theme/image/:type Get a theme image + * @apiName GetThemeImage + * @apiGroup Theme + * @apiParam {String="logo","background"} type Image type + * @apiSuccess {String} image The whole response is the image + * @apiPermission none + * @apiVersion 1.5.0 + * + * @param type Image type + * @return Response + */ @GET @Produces("image/*") @Path("image/{type: logo|background}") diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/UserResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/UserResource.java index 433812ec..d32042dd 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/UserResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/UserResource.java @@ -67,7 +67,23 @@ 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 (client) ForbiddenError Access denied + * @apiError (client) ValidationError Validation error + * @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.5.0 + * * @param username User's username * @param password Password * @param email E-Mail @@ -88,7 +104,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 +131,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 +142,19 @@ 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 + * @apiError (client) ForbiddenError Access denied + * @apiError (client) ValidationError Validation error + * @apiPermission user + * @apiVersion 1.5.0 + * * @param password Password * @param email E-Mail * @return Response @@ -142,7 +169,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 +192,22 @@ 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) ForbiddenError Access denied + * @apiError (client) ValidationError Validation error + * @apiError (client) UserNotFound User not found + * @apiPermission admin + * @apiVersion 1.5.0 + * * @param username Username * @param password Password * @param email E-Mail @@ -186,7 +227,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 +259,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.5.0 + * * @param username Username to check * @return Response */ @@ -244,7 +294,22 @@ 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) ForbiddenError Access denied + * @apiError (client) ValidationCodeRequired A TOTP validation code is required + * @apiPermission none + * @apiVersion 1.5.0 + * * @param username Username * @param password Password * @param longLasted Remember the user next time, create a long lasted session. @@ -309,7 +374,17 @@ 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 (client) ForbiddenError Access denied + * @apiError (server) AuthenticationTokenError Error deleting the authentication token + * @apiPermission user + * @apiVersion 1.5.0 + * * @return Response */ @POST @@ -337,7 +412,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 +422,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 Access denied or the admin user cannot be deleted + * @apiPermission user + * @apiVersion 1.5.0 + * * @return Response */ @DELETE @@ -396,7 +480,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) ForbiddenError Access denied or the admin user cannot be deleted + * @apiError (client) UserNotFound The user does not exist + * @apiPermission admin + * @apiVersion 1.5.0 + * * @param username Username * @return Response */ @@ -412,7 +506,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 +549,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.5.0 + * * @return Response */ @GET @@ -513,7 +622,21 @@ 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) ForbiddenError Access denied + * @apiError (client) UserNotFound The user does not exist + * @apiPermission user + * @apiVersion 1.5.0 + * * @param username Username * @return Response */ @@ -528,7 +651,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 +675,24 @@ 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 + * @apiParam {Boolean} asc If true, sort in ascending order + * @apiParam {String} group Filter on this group + * @apiSuccess {Object[]} 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) + * @apiError (client) ForbiddenError Access denied + * @apiPermission user + * @apiVersion 1.5.0 + * * @param sortColumn Sort index * @param asc If true, ascending sorting, else descending * @param groupName Only return users from this group @@ -600,7 +740,21 @@ 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 {Object[]} 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 + * @apiError (client) ForbiddenError Access denied + * @apiPermission user + * @apiVersion 1.5.0 + * * @return Response */ @GET @@ -635,7 +789,16 @@ 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 + * @apiError (client) ForbiddenError Access denied + * @apiPermission user + * @apiVersion 1.5.0 + * * @return Response */ @DELETE @@ -660,7 +823,17 @@ 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 + * @apiError (client) ForbiddenError Access denied + * @apiPermission user + * @apiVersion 1.5.0 + * * @return Response */ @POST @@ -687,7 +860,17 @@ 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 + * @apiError (client) ForbiddenError Access denied + * @apiError (client) ValidationError Validation error + * @apiPermission user + * @apiVersion 1.5.0 + * * @param password Password * @return Response */ @@ -720,7 +903,7 @@ public class UserResource extends BaseResource { /** * Returns the authentication token value. - * + * * @return Token value */ private String getAuthToken() { diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/VocabularyResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/VocabularyResource.java index 06ba5ee8..6dfef3b0 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/VocabularyResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/VocabularyResource.java @@ -20,6 +20,25 @@ 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 {Object[]} 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 + * @apiError (client) ForbiddenError Access denied + * @apiPermission user + * @apiVersion 1.5.0 + * + * @param name Name + * @return Response + */ @GET @Path("{name: [a-z0-9\\-]+}") public Response get(@PathParam("name") String name) { @@ -46,8 +65,23 @@ 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 + * @apiError (client) ForbiddenError Access denied + * @apiError (client) ValidationError Validation error + * @apiPermission admin + * @apiVersion 1.5.0 + * * @param name Name * @param value Value * @param orderStr Order @@ -86,7 +120,24 @@ 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 + * @apiError (client) ForbiddenError Access denied + * @apiError (client) ValidationError Validation error + * @apiError (client) NotFound Vocabulary not found + * @apiPermission admin + * @apiVersion 1.5.0 * * @param id ID * @param name Name @@ -145,8 +196,18 @@ 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 + * @apiError (client) ForbiddenError Access denied + * @apiError (client) NotFound Vocabulary not found + * @apiPermission admin + * @apiVersion 1.5.0 + * * @param id ID * @return Response */ diff --git a/docs-web/src/main/webapp/Gruntfile.js b/docs-web/src/main/webapp/Gruntfile.js index 5dba6d2d..ec2c6404 100644 --- a/docs-web/src/main/webapp/Gruntfile.js +++ b/docs-web/src/main/webapp/Gruntfile.js @@ -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']); }; \ No newline at end of file diff --git a/docs-web/src/main/webapp/package.json b/docs-web/src/main/webapp/package.json index 29eefd62..97c22aee 100644 --- a/docs-web/src/main/webapp/package.json +++ b/docs-web/src/main/webapp/package.json @@ -2,25 +2,48 @@ "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 + }, + "order": [ + "User", + "Group", + "Document", + "File", + "Tag", + "Comment", + "Share", + "Acl", + "Auditlog", + "App", + "Theme", + "Vocabulary" + ] + }, "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" } } diff --git a/docs-web/src/main/webapp/src/partial/docs/document.default.html b/docs-web/src/main/webapp/src/partial/docs/document.default.html index 0d814030..c15b146b 100644 --- a/docs-web/src/main/webapp/src/partial/docs/document.default.html +++ b/docs-web/src/main/webapp/src/partial/docs/document.default.html @@ -51,6 +51,8 @@
diff --git a/docs-web/src/main/webapp/src/partial/docs/document.view.html b/docs-web/src/main/webapp/src/partial/docs/document.view.html index a6a7fb94..3e94f557 100644 --- a/docs-web/src/main/webapp/src/partial/docs/document.view.html +++ b/docs-web/src/main/webapp/src/partial/docs/document.view.html @@ -12,8 +12,8 @@
-
-