mirror of
https://github.com/sismics/docs.git
synced 2024-11-25 23:27:57 +01:00
commit
3a22132363
2
.gitignore
vendored
2
.gitignore
vendored
@ -5,7 +5,7 @@
|
|||||||
/*/gen
|
/*/gen
|
||||||
/*/target
|
/*/target
|
||||||
/*/build
|
/*/build
|
||||||
/*/*.iml
|
|
||||||
/out
|
/out
|
||||||
/.idea
|
/.idea
|
||||||
/.project
|
/.project
|
||||||
|
*.iml
|
||||||
|
11
.travis.yml
Normal file
11
.travis.yml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
sudo: required
|
||||||
|
dist: trusty
|
||||||
|
language: java
|
||||||
|
before_install:
|
||||||
|
- sudo apt-get -qq update
|
||||||
|
- sudo apt-get -y -q install tesseract-ocr tesseract-ocr-fra tesseract-ocr-jpn
|
||||||
|
- sudo apt-get -y -q install haveged && sudo service haveged start
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- TESSDATA_PREFIX=/usr/share/tesseract-ocr
|
||||||
|
- LC_NUMERIC=C
|
@ -1,4 +1,4 @@
|
|||||||
Sismics Docs
|
Sismics Docs [![Build Status](https://secure.travis-ci.org/sismics/docs.png)](http://travis-ci.org/sismics/docs)
|
||||||
============
|
============
|
||||||
|
|
||||||
_Web interface_
|
_Web interface_
|
||||||
@ -50,7 +50,6 @@ Prerequisites: JDK 7 with JCE, Maven 3, Tesseract 3.02
|
|||||||
|
|
||||||
Docs is organized in several Maven modules:
|
Docs is organized in several Maven modules:
|
||||||
|
|
||||||
- docs-parent
|
|
||||||
- docs-core
|
- docs-core
|
||||||
- docs-web
|
- docs-web
|
||||||
- docs-web-common
|
- docs-web-common
|
||||||
@ -60,7 +59,7 @@ or download the sources from GitHub.
|
|||||||
|
|
||||||
#### Launch the build
|
#### Launch the build
|
||||||
|
|
||||||
From the `docs-parent` directory:
|
From the root directory:
|
||||||
|
|
||||||
mvn clean -DskipTests install
|
mvn clean -DskipTests install
|
||||||
|
|
||||||
|
@ -1,115 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="docs-android" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
|
||||||
<component name="FacetManager">
|
|
||||||
<facet type="android-gradle" name="Android-Gradle">
|
|
||||||
<configuration>
|
|
||||||
<option name="GRADLE_PROJECT_PATH" value=":app" />
|
|
||||||
</configuration>
|
|
||||||
</facet>
|
|
||||||
<facet type="android" name="Android">
|
|
||||||
<configuration>
|
|
||||||
<option name="SELECTED_BUILD_VARIANT" value="debug" />
|
|
||||||
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
|
|
||||||
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
|
|
||||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
|
|
||||||
<afterSyncTasks>
|
|
||||||
<task>generateDebugSources</task>
|
|
||||||
</afterSyncTasks>
|
|
||||||
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
|
||||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
|
||||||
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
|
|
||||||
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
|
|
||||||
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
|
|
||||||
</configuration>
|
|
||||||
</facet>
|
|
||||||
</component>
|
|
||||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
|
|
||||||
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
|
|
||||||
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
|
|
||||||
<exclude-output />
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/jni" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/animated-vector-drawable/23.2.1/jars" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.2.1/jars" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/design/23.2.1/jars" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/recyclerview-v7/23.2.1/jars" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/23.2.1/jars" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-vector-drawable/23.2.1/jars" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/it.sephiroth.android.library.easing/android-easing/1.0.3/jars" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/it.sephiroth.android.library.imagezoom/imagezoom/1.0.5/jars" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
<orderEntry type="library" exported="" name="support-v4-23.2.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="android-easing-1.0.3" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="imagezoom-1.0.5" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="design-23.2.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="okhttp-urlconnection-3.1.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="picasso-2.5.2" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="animated-vector-drawable-23.2.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="recyclerview-v7-23.2.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-annotations-23.2.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="okhttp-3.1.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="okio-1.6.0" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-vector-drawable-23.2.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="picasso2-okhttp3-downloader-1.0.2" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="tokenautocomplete-1.2.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="appcompat-v7-23.2.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="eventbus-3.0.0" level="project" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
@ -3,7 +3,7 @@ buildscript {
|
|||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:2.1.0-alpha3'
|
classpath 'com.android.tools.build:gradle:2.1.0-beta1'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
@ -14,7 +14,7 @@ repositories {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 23
|
compileSdkVersion 23
|
||||||
buildToolsVersion '23.0.2'
|
buildToolsVersion '23.0.3'
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
@ -50,9 +50,9 @@ android {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile fileTree(dir: 'libs', include: '*.jar')
|
compile fileTree(dir: 'libs', include: '*.jar')
|
||||||
compile 'com.android.support:appcompat-v7:23.2.1'
|
compile 'com.android.support:appcompat-v7:23.3.0'
|
||||||
compile 'com.android.support:recyclerview-v7:23.2.1'
|
compile 'com.android.support:recyclerview-v7:23.3.0'
|
||||||
compile 'com.android.support:design:23.2.1'
|
compile 'com.android.support:design:23.3.0'
|
||||||
compile 'it.sephiroth.android.library.imagezoom:imagezoom:1.0.5'
|
compile 'it.sephiroth.android.library.imagezoom:imagezoom:1.0.5'
|
||||||
compile 'org.greenrobot:eventbus:3.0.0'
|
compile 'org.greenrobot:eventbus:3.0.0'
|
||||||
compile 'com.squareup.picasso:picasso:2.5.2'
|
compile 'com.squareup.picasso:picasso:2.5.2'
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.sismics.docs" >
|
package="com.sismics.docs"
|
||||||
|
android:installLocation="auto">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
@ -48,6 +48,7 @@ public class LoginActivity extends AppCompatActivity {
|
|||||||
final EditText txtServer = (EditText) findViewById(R.id.txtServer);
|
final EditText txtServer = (EditText) findViewById(R.id.txtServer);
|
||||||
final EditText txtUsername = (EditText) findViewById(R.id.txtUsername);
|
final EditText txtUsername = (EditText) findViewById(R.id.txtUsername);
|
||||||
final EditText txtPassword = (EditText) findViewById(R.id.txtPassword);
|
final EditText txtPassword = (EditText) findViewById(R.id.txtPassword);
|
||||||
|
final EditText txtValidationCode = (EditText) findViewById(R.id.txtValidationCode);
|
||||||
final Button btnConnect = (Button) findViewById(R.id.btnConnect);
|
final Button btnConnect = (Button) findViewById(R.id.btnConnect);
|
||||||
loginForm = findViewById(R.id.loginForm);
|
loginForm = findViewById(R.id.loginForm);
|
||||||
progressBar = findViewById(R.id.progressBar);
|
progressBar = findViewById(R.id.progressBar);
|
||||||
@ -87,7 +88,9 @@ public class LoginActivity extends AppCompatActivity {
|
|||||||
PreferenceUtil.setServerUrl(LoginActivity.this, txtServer.getText().toString());
|
PreferenceUtil.setServerUrl(LoginActivity.this, txtServer.getText().toString());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
UserResource.login(getApplicationContext(), txtUsername.getText().toString(), txtPassword.getText().toString(), new HttpCallback() {
|
UserResource.login(getApplicationContext(), txtUsername.getText().toString(),
|
||||||
|
txtPassword.getText().toString(), txtValidationCode.getText().toString(),
|
||||||
|
new HttpCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(JSONObject json) {
|
public void onSuccess(JSONObject json) {
|
||||||
// Empty previous user caches
|
// Empty previous user caches
|
||||||
@ -111,6 +114,10 @@ public class LoginActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
if (json != null && json.optString("type").equals("ForbiddenError")) {
|
if (json != null && json.optString("type").equals("ForbiddenError")) {
|
||||||
DialogUtil.showOkDialog(LoginActivity.this, R.string.login_fail_title, R.string.login_fail);
|
DialogUtil.showOkDialog(LoginActivity.this, R.string.login_fail_title, R.string.login_fail);
|
||||||
|
} else if (json != null && json.optString("type").equals("ValidationCodeRequired")) {
|
||||||
|
txtValidationCode.setVisibility(View.VISIBLE);
|
||||||
|
validator.addValidable(txtValidationCode, new Required());
|
||||||
|
validator.validate();
|
||||||
} else {
|
} else {
|
||||||
DialogUtil.showOkDialog(LoginActivity.this, R.string.network_error_title, R.string.network_error);
|
DialogUtil.showOkDialog(LoginActivity.this, R.string.network_error_title, R.string.network_error);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package com.sismics.docs.adapter;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.text.format.DateFormat;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@ -15,6 +16,7 @@ import org.json.JSONArray;
|
|||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,8 +87,11 @@ public class AuditLogListAdapter extends BaseAdapter {
|
|||||||
// Fill the view
|
// Fill the view
|
||||||
TextView usernameTextView = (TextView) view.findViewById(R.id.usernameTextView);
|
TextView usernameTextView = (TextView) view.findViewById(R.id.usernameTextView);
|
||||||
TextView messageTextView = (TextView) view.findViewById(R.id.messageTextView);
|
TextView messageTextView = (TextView) view.findViewById(R.id.messageTextView);
|
||||||
|
TextView dateTextView = (TextView) view.findViewById(R.id.dateTextView);
|
||||||
usernameTextView.setText(log.optString("username"));
|
usernameTextView.setText(log.optString("username"));
|
||||||
messageTextView.setText(message);
|
messageTextView.setText(message);
|
||||||
|
String date = DateFormat.getDateFormat(parent.getContext()).format(new Date(log.optLong("create_date")));
|
||||||
|
dateTextView.setText(date);
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
@ -24,12 +24,13 @@ public class UserResource extends BaseResource {
|
|||||||
* @param password Password
|
* @param password Password
|
||||||
* @param callback Callback
|
* @param callback Callback
|
||||||
*/
|
*/
|
||||||
public static void login(Context context, String username, String password, HttpCallback callback) {
|
public static void login(Context context, String username, String password, String code, HttpCallback callback) {
|
||||||
Request request = new Request.Builder()
|
Request request = new Request.Builder()
|
||||||
.url(HttpUrl.parse(getApiUrl(context) + "/user/login"))
|
.url(HttpUrl.parse(getApiUrl(context) + "/user/login"))
|
||||||
.post(new FormBody.Builder()
|
.post(new FormBody.Builder()
|
||||||
.add("username", username)
|
.add("username", username)
|
||||||
.add("password", password)
|
.add("password", password)
|
||||||
|
.add("code", code)
|
||||||
.add("remember", "true")
|
.add("remember", "true")
|
||||||
.build())
|
.build())
|
||||||
.build();
|
.build();
|
||||||
|
@ -61,6 +61,17 @@
|
|||||||
android:inputType="textPassword">
|
android:inputType="textPassword">
|
||||||
</EditText>
|
</EditText>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:visibility="gone"
|
||||||
|
android:id="@+id/txtValidationCode"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0.5"
|
||||||
|
android:ems="10"
|
||||||
|
android:hint="@string/validation_code"
|
||||||
|
android:inputType="number">
|
||||||
|
</EditText>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/btnConnect"
|
android:id="@+id/btnConnect"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
|
@ -131,5 +131,6 @@
|
|||||||
<string name="email">E-mail</string>
|
<string name="email">E-mail</string>
|
||||||
<string name="storage_quota">Storage quota</string>
|
<string name="storage_quota">Storage quota</string>
|
||||||
<string name="storage_display">%1$d/%2$d MB</string>
|
<string name="storage_display">%1$d/%2$d MB</string>
|
||||||
|
<string name="validation_code">Validation code</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<groupId>com.sismics.docs</groupId>
|
<groupId>com.sismics.docs</groupId>
|
||||||
<artifactId>docs-parent</artifactId>
|
<artifactId>docs-parent</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
<relativePath>../docs-parent</relativePath>
|
<relativePath>..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
@ -10,4 +10,8 @@ public enum ConfigType {
|
|||||||
* Lucene directory storage type.
|
* Lucene directory storage type.
|
||||||
*/
|
*/
|
||||||
LUCENE_DIRECTORY_STORAGE,
|
LUCENE_DIRECTORY_STORAGE,
|
||||||
|
/**
|
||||||
|
* Theme configuration.
|
||||||
|
*/
|
||||||
|
THEME
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,6 @@ public class AclDao {
|
|||||||
* @param acl ACL
|
* @param acl ACL
|
||||||
* @param userId User ID
|
* @param userId User ID
|
||||||
* @return New ID
|
* @return New ID
|
||||||
* @throws Exception
|
|
||||||
*/
|
*/
|
||||||
public String create(Acl acl, String userId) {
|
public String create(Acl acl, String userId) {
|
||||||
// Create the UUID
|
// Create the UUID
|
||||||
@ -82,7 +81,7 @@ public class AclDao {
|
|||||||
List<Object[]> l = q.getResultList();
|
List<Object[]> l = q.getResultList();
|
||||||
|
|
||||||
// Assemble results
|
// Assemble results
|
||||||
List<AclDto> aclDtoList = new ArrayList<AclDto>();
|
List<AclDto> aclDtoList = new ArrayList<>();
|
||||||
for (Object[] o : l) {
|
for (Object[] o : l) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
AclDto aclDto = new AclDto();
|
AclDto aclDto = new AclDto();
|
||||||
@ -92,7 +91,7 @@ public class AclDao {
|
|||||||
String userName = (String) o[i++];
|
String userName = (String) o[i++];
|
||||||
String shareId = (String) o[i++];
|
String shareId = (String) o[i++];
|
||||||
String shareName = (String) o[i++];
|
String shareName = (String) o[i++];
|
||||||
String groupName = (String) o[i++];
|
String groupName = (String) o[i];
|
||||||
if (userName != null) {
|
if (userName != null) {
|
||||||
aclDto.setTargetName(userName);
|
aclDto.setTargetName(userName);
|
||||||
aclDto.setTargetType(AclTargetType.USER.name());
|
aclDto.setTargetType(AclTargetType.USER.name());
|
||||||
@ -114,23 +113,25 @@ public class AclDao {
|
|||||||
* Check if a source is accessible to a target.
|
* Check if a source is accessible to a target.
|
||||||
*
|
*
|
||||||
* @param sourceId ACL source entity ID
|
* @param sourceId ACL source entity ID
|
||||||
* @parm perm Necessary permission
|
* @param perm Necessary permission
|
||||||
* @param targetId ACL target entity ID
|
* @param targetIdList List of targets
|
||||||
* @return True if the document is accessible
|
* @return True if the document is accessible
|
||||||
*/
|
*/
|
||||||
public boolean checkPermission(String sourceId, PermType perm, List<String> targetIdList) {
|
public boolean checkPermission(String sourceId, PermType perm, List<String> targetIdList) {
|
||||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||||
Query q = em.createQuery("select a from Acl a where a.sourceId = :sourceId and a.perm = :perm and a.targetId in (:targetIdList) and a.deleteDate is null");
|
StringBuilder sb = new StringBuilder("select a.ACL_ID_C from T_ACL a ");
|
||||||
|
sb.append(" where a.ACL_TARGETID_C in (:targetIdList) and a.ACL_SOURCEID_C = :sourceId and a.ACL_PERM_C = :perm and a.ACL_DELETEDATE_D is null ");
|
||||||
|
sb.append(" union all ");
|
||||||
|
sb.append(" select a.ACL_ID_C from T_ACL a, T_DOCUMENT_TAG dt ");
|
||||||
|
sb.append(" where a.ACL_SOURCEID_C = dt.DOT_IDTAG_C and dt.DOT_IDDOCUMENT_C = :sourceId and dt.DOT_DELETEDATE_D is null ");
|
||||||
|
sb.append(" and a.ACL_TARGETID_C in (:targetIdList) and a.ACL_PERM_C = :perm and a.ACL_DELETEDATE_D is null ");
|
||||||
|
Query q = em.createNativeQuery(sb.toString());
|
||||||
q.setParameter("sourceId", sourceId);
|
q.setParameter("sourceId", sourceId);
|
||||||
q.setParameter("perm", perm);
|
q.setParameter("perm", perm.name());
|
||||||
q.setParameter("targetIdList", targetIdList);
|
q.setParameter("targetIdList", targetIdList);
|
||||||
|
|
||||||
// We have a matching permission
|
// We have a matching permission
|
||||||
if (q.getResultList().size() > 0) {
|
return q.getResultList().size() > 0;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,4 +33,23 @@ public class ConfigDao {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a configuration parameter.
|
||||||
|
*
|
||||||
|
* @param id Configuration parameter ID
|
||||||
|
* @param value Configuration parameter value
|
||||||
|
*/
|
||||||
|
public void update(ConfigType id, String value) {
|
||||||
|
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||||
|
Config config = getById(id);
|
||||||
|
if (config == null) {
|
||||||
|
config = new Config();
|
||||||
|
config.setId(id);
|
||||||
|
config.setValue(value);
|
||||||
|
em.persist(config);
|
||||||
|
} else {
|
||||||
|
config.setValue(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,7 @@ public class ContributorDao {
|
|||||||
* Creates a new contributor.
|
* Creates a new contributor.
|
||||||
*
|
*
|
||||||
* @param contributor Contributor
|
* @param contributor Contributor
|
||||||
* @param userId User ID
|
|
||||||
* @return New ID
|
* @return New ID
|
||||||
* @throws Exception
|
|
||||||
*/
|
*/
|
||||||
public String create(Contributor contributor) {
|
public String create(Contributor contributor) {
|
||||||
// Create the UUID
|
// Create the UUID
|
||||||
@ -72,7 +70,7 @@ public class ContributorDao {
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
ContributorDto contributorDto = new ContributorDto();
|
ContributorDto contributorDto = new ContributorDto();
|
||||||
contributorDto.setUsername((String) o[i++]);
|
contributorDto.setUsername((String) o[i++]);
|
||||||
contributorDto.setEmail((String) o[i++]);
|
contributorDto.setEmail((String) o[i]);
|
||||||
contributorDtoList.add(contributorDto);
|
contributorDtoList.add(contributorDto);
|
||||||
}
|
}
|
||||||
return contributorDtoList;
|
return contributorDtoList;
|
||||||
|
@ -40,7 +40,6 @@ public class DocumentDao {
|
|||||||
* @param document Document
|
* @param document Document
|
||||||
* @param userId User ID
|
* @param userId User ID
|
||||||
* @return New ID
|
* @return New ID
|
||||||
* @throws Exception
|
|
||||||
*/
|
*/
|
||||||
public String create(Document document, String userId) {
|
public String create(Document document, String userId) {
|
||||||
// Create the UUID
|
// Create the UUID
|
||||||
@ -87,10 +86,15 @@ public class DocumentDao {
|
|||||||
*
|
*
|
||||||
* @param id Document ID
|
* @param id Document ID
|
||||||
* @param perm Permission needed
|
* @param perm Permission needed
|
||||||
* @param userId User ID
|
* @param targetIdList List of targets
|
||||||
* @return Document
|
* @return Document
|
||||||
*/
|
*/
|
||||||
public DocumentDto getDocument(String id, PermType perm, List<String> targetIdList) {
|
public DocumentDto getDocument(String id, PermType perm, List<String> targetIdList) {
|
||||||
|
AclDao aclDao = new AclDao();
|
||||||
|
if (!aclDao.checkPermission(id, perm, targetIdList)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||||
StringBuilder sb = new StringBuilder("select distinct d.DOC_ID_C, d.DOC_TITLE_C, d.DOC_DESCRIPTION_C, d.DOC_SUBJECT_C, d.DOC_IDENTIFIER_C, d.DOC_PUBLISHER_C, d.DOC_FORMAT_C, d.DOC_SOURCE_C, d.DOC_TYPE_C, d.DOC_COVERAGE_C, d.DOC_RIGHTS_C, d.DOC_CREATEDATE_D, d.DOC_LANGUAGE_C, ");
|
StringBuilder sb = new StringBuilder("select distinct d.DOC_ID_C, d.DOC_TITLE_C, d.DOC_DESCRIPTION_C, d.DOC_SUBJECT_C, d.DOC_IDENTIFIER_C, d.DOC_PUBLISHER_C, d.DOC_FORMAT_C, d.DOC_SOURCE_C, d.DOC_TYPE_C, d.DOC_COVERAGE_C, d.DOC_RIGHTS_C, d.DOC_CREATEDATE_D, d.DOC_LANGUAGE_C, ");
|
||||||
sb.append(" (select count(s.SHA_ID_C) from T_SHARE s, T_ACL ac where ac.ACL_SOURCEID_C = d.DOC_ID_C and ac.ACL_TARGETID_C = s.SHA_ID_C and ac.ACL_DELETEDATE_D is null and s.SHA_DELETEDATE_D is null), ");
|
sb.append(" (select count(s.SHA_ID_C) from T_SHARE s, T_ACL ac where ac.ACL_SOURCEID_C = d.DOC_ID_C and ac.ACL_TARGETID_C = s.SHA_ID_C and ac.ACL_DELETEDATE_D is null and s.SHA_DELETEDATE_D is null), ");
|
||||||
@ -98,15 +102,12 @@ public class DocumentDao {
|
|||||||
sb.append(" u.USE_USERNAME_C ");
|
sb.append(" u.USE_USERNAME_C ");
|
||||||
sb.append(" from T_DOCUMENT d ");
|
sb.append(" from T_DOCUMENT d ");
|
||||||
sb.append(" join T_USER u on d.DOC_IDUSER_C = u.USE_ID_C ");
|
sb.append(" join T_USER u on d.DOC_IDUSER_C = u.USE_ID_C ");
|
||||||
sb.append(" left join T_ACL a on a.ACL_SOURCEID_C = d.DOC_ID_C and a.ACL_TARGETID_C in (:targetIdList) and a.ACL_PERM_C = :perm and a.ACL_DELETEDATE_D is null ");
|
sb.append(" where d.DOC_ID_C = :id and d.DOC_DELETEDATE_D is null ");
|
||||||
sb.append(" where d.DOC_ID_C = :id and a.ACL_ID_C is not null and d.DOC_DELETEDATE_D is null ");
|
|
||||||
|
|
||||||
Query q = em.createNativeQuery(sb.toString());
|
Query q = em.createNativeQuery(sb.toString());
|
||||||
q.setParameter("id", id);
|
q.setParameter("id", id);
|
||||||
q.setParameter("perm", perm.name());
|
|
||||||
q.setParameter("targetIdList", targetIdList);
|
|
||||||
|
|
||||||
Object[] o = null;
|
Object[] o;
|
||||||
try {
|
try {
|
||||||
o = (Object[]) q.getSingleResult();
|
o = (Object[]) q.getSingleResult();
|
||||||
} catch (NoResultException e) {
|
} catch (NoResultException e) {
|
||||||
@ -130,7 +131,7 @@ public class DocumentDao {
|
|||||||
documentDto.setLanguage((String) o[i++]);
|
documentDto.setLanguage((String) o[i++]);
|
||||||
documentDto.setShared(((Number) o[i++]).intValue() > 0);
|
documentDto.setShared(((Number) o[i++]).intValue() > 0);
|
||||||
documentDto.setFileCount(((Number) o[i++]).intValue());
|
documentDto.setFileCount(((Number) o[i++]).intValue());
|
||||||
documentDto.setCreator((String) o[i++]);
|
documentDto.setCreator((String) o[i]);
|
||||||
return documentDto;
|
return documentDto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,22 +201,24 @@ public class DocumentDao {
|
|||||||
* @param paginatedList List of documents (updated by side effects)
|
* @param paginatedList List of documents (updated by side effects)
|
||||||
* @param criteria Search criteria
|
* @param criteria Search criteria
|
||||||
* @param sortCriteria Sort criteria
|
* @param sortCriteria Sort criteria
|
||||||
* @return List of documents
|
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public void findByCriteria(PaginatedList<DocumentDto> paginatedList, DocumentCriteria criteria, SortCriteria sortCriteria) throws Exception {
|
public void findByCriteria(PaginatedList<DocumentDto> paginatedList, DocumentCriteria criteria, SortCriteria sortCriteria) throws Exception {
|
||||||
Map<String, Object> parameterMap = new HashMap<String, Object>();
|
Map<String, Object> parameterMap = new HashMap<>();
|
||||||
List<String> criteriaList = new ArrayList<String>();
|
List<String> criteriaList = new ArrayList<>();
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder("select distinct d.DOC_ID_C c0, d.DOC_TITLE_C c1, d.DOC_DESCRIPTION_C c2, d.DOC_CREATEDATE_D c3, d.DOC_LANGUAGE_C c4, ");
|
StringBuilder sb = new StringBuilder("select distinct d.DOC_ID_C c0, d.DOC_TITLE_C c1, d.DOC_DESCRIPTION_C c2, d.DOC_CREATEDATE_D c3, d.DOC_LANGUAGE_C c4, ");
|
||||||
sb.append(" (select count(s.SHA_ID_C) from T_SHARE s, T_ACL ac where ac.ACL_SOURCEID_C = d.DOC_ID_C and ac.ACL_TARGETID_C = s.SHA_ID_C and ac.ACL_DELETEDATE_D is null and s.SHA_DELETEDATE_D is null) c5, ");
|
sb.append(" (select count(s.SHA_ID_C) from T_SHARE s, T_ACL ac where ac.ACL_SOURCEID_C = d.DOC_ID_C and ac.ACL_TARGETID_C = s.SHA_ID_C and ac.ACL_DELETEDATE_D is null and s.SHA_DELETEDATE_D is null) c5, ");
|
||||||
sb.append(" (select count(f.FIL_ID_C) from T_FILE f where f.FIL_DELETEDATE_D is null and f.FIL_IDDOC_C = d.DOC_ID_C) c6 ");
|
sb.append(" (select count(f.FIL_ID_C) from T_FILE f where f.FIL_DELETEDATE_D is null and f.FIL_IDDOC_C = d.DOC_ID_C) c6 ");
|
||||||
sb.append(" from T_DOCUMENT d ");
|
sb.append(" from T_DOCUMENT d ");
|
||||||
|
|
||||||
// Adds search criteria
|
// Add search criterias
|
||||||
if (criteria.getTargetIdList() != null) {
|
if (criteria.getTargetIdList() != null) {
|
||||||
// Read permission is enough for searching
|
// Read permission is enough for searching
|
||||||
sb.append(" join T_ACL a on a.ACL_SOURCEID_C = d.DOC_ID_C and a.ACL_TARGETID_C in (:targetIdList) and a.ACL_PERM_C = 'READ' and a.ACL_DELETEDATE_D is null ");
|
sb.append(" left join T_ACL a on a.ACL_TARGETID_C in (:targetIdList) and a.ACL_SOURCEID_C = d.DOC_ID_C and a.ACL_PERM_C = 'READ' and a.ACL_DELETEDATE_D is null ");
|
||||||
|
sb.append(" left join T_DOCUMENT_TAG dta on dta.DOT_IDDOCUMENT_C = d.DOC_ID_C and dta.DOT_DELETEDATE_D is null ");
|
||||||
|
sb.append(" left join T_ACL a2 on a2.ACL_TARGETID_C in (:targetIdList) and a2.ACL_SOURCEID_C = dta.DOT_IDTAG_C and a2.ACL_PERM_C = 'READ' and a2.ACL_DELETEDATE_D is null ");
|
||||||
|
criteriaList.add("(a.ACL_ID_C is not null or a2.ACL_ID_C is not null)");
|
||||||
parameterMap.put("targetIdList", criteria.getTargetIdList());
|
parameterMap.put("targetIdList", criteria.getTargetIdList());
|
||||||
}
|
}
|
||||||
if (!Strings.isNullOrEmpty(criteria.getSearch()) || !Strings.isNullOrEmpty(criteria.getFullSearch())) {
|
if (!Strings.isNullOrEmpty(criteria.getSearch()) || !Strings.isNullOrEmpty(criteria.getFullSearch())) {
|
||||||
@ -239,7 +242,7 @@ public class DocumentDao {
|
|||||||
if (criteria.getTagIdList() != null && !criteria.getTagIdList().isEmpty()) {
|
if (criteria.getTagIdList() != null && !criteria.getTagIdList().isEmpty()) {
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (String tagId : criteria.getTagIdList()) {
|
for (String tagId : criteria.getTagIdList()) {
|
||||||
sb.append(" join T_DOCUMENT_TAG dt" + index + " on dt" + index + ".DOT_IDDOCUMENT_C = d.DOC_ID_C and dt" + index + ".DOT_IDTAG_C = :tagId" + index + " and dt" + index + ".DOT_DELETEDATE_D is null ");
|
sb.append(String.format(" join T_DOCUMENT_TAG dt%d on dt%d.DOT_IDDOCUMENT_C = d.DOC_ID_C and dt%d.DOT_IDTAG_C = :tagId%d and dt%d.DOT_DELETEDATE_D is null ", index, index, index, index, index));
|
||||||
parameterMap.put("tagId" + index, tagId);
|
parameterMap.put("tagId" + index, tagId);
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
@ -278,7 +281,7 @@ public class DocumentDao {
|
|||||||
documentDto.setCreateTimestamp(((Timestamp) o[i++]).getTime());
|
documentDto.setCreateTimestamp(((Timestamp) o[i++]).getTime());
|
||||||
documentDto.setLanguage((String) o[i++]);
|
documentDto.setLanguage((String) o[i++]);
|
||||||
documentDto.setShared(((Number) o[i++]).intValue() > 0);
|
documentDto.setShared(((Number) o[i++]).intValue() > 0);
|
||||||
documentDto.setFileCount(((Number) o[i++]).intValue());
|
documentDto.setFileCount(((Number) o[i]).intValue());
|
||||||
documentDtoList.add(documentDto);
|
documentDtoList.add(documentDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,6 @@ public class FileDao {
|
|||||||
* @param file File
|
* @param file File
|
||||||
* @param userId User ID
|
* @param userId User ID
|
||||||
* @return New ID
|
* @return New ID
|
||||||
* @throws Exception
|
|
||||||
*/
|
*/
|
||||||
public String create(File file, String userId) {
|
public String create(File file, String userId) {
|
||||||
// Create the UUID
|
// Create the UUID
|
||||||
@ -155,10 +154,12 @@ public class FileDao {
|
|||||||
* @param id File ID
|
* @param id File ID
|
||||||
* @return File
|
* @return File
|
||||||
*/
|
*/
|
||||||
public File getById(String id) {
|
public File getActiveById(String id) {
|
||||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||||
|
Query q = em.createQuery("select f from File f where f.id = :id and f.deleteDate is null");
|
||||||
|
q.setParameter("id", id);
|
||||||
try {
|
try {
|
||||||
return em.find(File.class, id);
|
return (File) q.getSingleResult();
|
||||||
} catch (NoResultException e) {
|
} catch (NoResultException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -167,7 +168,7 @@ public class FileDao {
|
|||||||
/**
|
/**
|
||||||
* Get files by document ID or all orphan files of an user.
|
* Get files by document ID or all orphan files of an user.
|
||||||
*
|
*
|
||||||
* @parma userId User ID
|
* @param userId User ID
|
||||||
* @param documentId Document ID
|
* @param documentId Document ID
|
||||||
* @return List of files
|
* @return List of files
|
||||||
*/
|
*/
|
||||||
|
@ -71,7 +71,6 @@ public class GroupDao {
|
|||||||
* @param group Group
|
* @param group Group
|
||||||
* @param userId User ID
|
* @param userId User ID
|
||||||
* @return New ID
|
* @return New ID
|
||||||
* @throws Exception
|
|
||||||
*/
|
*/
|
||||||
public String create(Group group, String userId) {
|
public String create(Group group, String userId) {
|
||||||
// Create the UUID
|
// Create the UUID
|
||||||
@ -127,9 +126,8 @@ public class GroupDao {
|
|||||||
/**
|
/**
|
||||||
* Add an user to a group.
|
* Add an user to a group.
|
||||||
*
|
*
|
||||||
* @param group Group
|
* @param userGroup User group
|
||||||
* @return New ID
|
* @return New ID
|
||||||
* @throws Exception
|
|
||||||
*/
|
*/
|
||||||
public String addMember(UserGroup userGroup) {
|
public String addMember(UserGroup userGroup) {
|
||||||
// Create the UUID
|
// Create the UUID
|
||||||
@ -170,8 +168,8 @@ public class GroupDao {
|
|||||||
* @return List of groups
|
* @return List of groups
|
||||||
*/
|
*/
|
||||||
public List<GroupDto> findByCriteria(GroupCriteria criteria, SortCriteria sortCriteria) {
|
public List<GroupDto> findByCriteria(GroupCriteria criteria, SortCriteria sortCriteria) {
|
||||||
Map<String, Object> parameterMap = new HashMap<String, Object>();
|
Map<String, Object> parameterMap = new HashMap<>();
|
||||||
List<String> criteriaList = new ArrayList<String>();
|
List<String> criteriaList = new ArrayList<>();
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder("select g.GRP_ID_C as c0, g.GRP_NAME_C as c1, g.GRP_IDPARENT_C as c2, gp.GRP_NAME_C as c3, g.GRP_IDROLE_C ");
|
StringBuilder sb = new StringBuilder("select g.GRP_ID_C as c0, g.GRP_NAME_C as c1, g.GRP_IDPARENT_C as c2, gp.GRP_NAME_C as c3, g.GRP_IDROLE_C ");
|
||||||
if (criteria.getUserId() != null) {
|
if (criteria.getUserId() != null) {
|
||||||
@ -187,8 +185,8 @@ public class GroupDao {
|
|||||||
}
|
}
|
||||||
if (criteria.getUserId() != null) {
|
if (criteria.getUserId() != null) {
|
||||||
// Left join and post-filtering for recursive groups
|
// Left join and post-filtering for recursive groups
|
||||||
sb.append((criteria.isRecursive() ? " left " : "")
|
sb.append(criteria.isRecursive() ? " left " : "");
|
||||||
+ " join T_USER_GROUP ug on ug.UGP_IDGROUP_C = g.GRP_ID_C and ug.UGP_IDUSER_C = :userId and ug.UGP_DELETEDATE_D is null ");
|
sb.append(" join T_USER_GROUP ug on ug.UGP_IDGROUP_C = g.GRP_ID_C and ug.UGP_IDUSER_C = :userId and ug.UGP_DELETEDATE_D is null ");
|
||||||
parameterMap.put("userId", criteria.getUserId());
|
parameterMap.put("userId", criteria.getUserId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,7 +214,7 @@ public class GroupDao {
|
|||||||
.setParentName((String) o[i++])
|
.setParentName((String) o[i++])
|
||||||
.setRoleId((String) o[i++]);
|
.setRoleId((String) o[i++]);
|
||||||
groupDtoList.add(groupDto);
|
groupDtoList.add(groupDto);
|
||||||
if (criteria.getUserId() != null && o[i++] != null) {
|
if (criteria.getUserId() != null && o[i] != null) {
|
||||||
userGroupDtoList.add(groupDto);
|
userGroupDtoList.add(groupDto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,24 @@
|
|||||||
package com.sismics.docs.core.dao.jpa;
|
package com.sismics.docs.core.dao.jpa;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.NoResultException;
|
import javax.persistence.NoResultException;
|
||||||
import javax.persistence.Query;
|
import javax.persistence.Query;
|
||||||
|
|
||||||
|
import com.google.common.base.Joiner;
|
||||||
import com.sismics.docs.core.constant.AuditLogType;
|
import com.sismics.docs.core.constant.AuditLogType;
|
||||||
|
import com.sismics.docs.core.dao.jpa.criteria.GroupCriteria;
|
||||||
|
import com.sismics.docs.core.dao.jpa.criteria.TagCriteria;
|
||||||
|
import com.sismics.docs.core.dao.jpa.dto.GroupDto;
|
||||||
import com.sismics.docs.core.dao.jpa.dto.TagDto;
|
import com.sismics.docs.core.dao.jpa.dto.TagDto;
|
||||||
import com.sismics.docs.core.dao.jpa.dto.TagStatDto;
|
import com.sismics.docs.core.dao.jpa.dto.TagStatDto;
|
||||||
import com.sismics.docs.core.model.jpa.DocumentTag;
|
import com.sismics.docs.core.model.jpa.DocumentTag;
|
||||||
import com.sismics.docs.core.model.jpa.Tag;
|
import com.sismics.docs.core.model.jpa.Tag;
|
||||||
import com.sismics.docs.core.util.AuditLogUtil;
|
import com.sismics.docs.core.util.AuditLogUtil;
|
||||||
|
import com.sismics.docs.core.util.jpa.QueryParam;
|
||||||
|
import com.sismics.docs.core.util.jpa.QueryUtil;
|
||||||
|
import com.sismics.docs.core.util.jpa.SortCriteria;
|
||||||
import com.sismics.util.context.ThreadLocalContext;
|
import com.sismics.util.context.ThreadLocalContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -39,19 +42,6 @@ public class TagDao {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the list of all tags.
|
|
||||||
*
|
|
||||||
* @return List of tags
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public List<Tag> getByUserId(String userId) {
|
|
||||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
|
||||||
Query q = em.createQuery("select t from Tag t where t.userId = :userId and t.deleteDate is null order by t.name");
|
|
||||||
q.setParameter("userId", userId);
|
|
||||||
return q.getResultList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update tags on a document.
|
* Update tags on a document.
|
||||||
*
|
*
|
||||||
@ -94,85 +84,12 @@ public class TagDao {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns tag list on a document.
|
|
||||||
*
|
|
||||||
* @param documentId Document ID
|
|
||||||
* @return List of tags
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public List<TagDto> getByDocumentId(String documentId, String userId) {
|
|
||||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
|
||||||
StringBuilder sb = new StringBuilder("select t.TAG_ID_C, t.TAG_NAME_C, t.TAG_COLOR_C, t.TAG_IDPARENT_C from T_DOCUMENT_TAG dt ");
|
|
||||||
sb.append(" join T_TAG t on t.TAG_ID_C = dt.DOT_IDTAG_C ");
|
|
||||||
sb.append(" where dt.DOT_IDDOCUMENT_C = :documentId and t.TAG_DELETEDATE_D is null ");
|
|
||||||
sb.append(" and t.TAG_IDUSER_C = :userId and dt.DOT_DELETEDATE_D is null ");
|
|
||||||
sb.append(" order by t.TAG_NAME_C ");
|
|
||||||
|
|
||||||
// Perform the query
|
|
||||||
Query q = em.createNativeQuery(sb.toString());
|
|
||||||
q.setParameter("documentId", documentId);
|
|
||||||
q.setParameter("userId", userId);
|
|
||||||
List<Object[]> l = q.getResultList();
|
|
||||||
|
|
||||||
// Assemble results
|
|
||||||
List<TagDto> tagDtoList = new ArrayList<TagDto>();
|
|
||||||
for (Object[] o : l) {
|
|
||||||
int i = 0;
|
|
||||||
TagDto tagDto = new TagDto();
|
|
||||||
tagDto.setId((String) o[i++]);
|
|
||||||
tagDto.setName((String) o[i++]);
|
|
||||||
tagDto.setColor((String) o[i++]);
|
|
||||||
tagDto.setParentId((String) o[i++]);
|
|
||||||
tagDtoList.add(tagDto);
|
|
||||||
}
|
|
||||||
return tagDtoList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns stats on tags.
|
|
||||||
*
|
|
||||||
* @param documentId Document ID
|
|
||||||
* @return Stats by tag
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public List<TagStatDto> getStats(String userId) {
|
|
||||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
|
||||||
StringBuilder sb = new StringBuilder("select t.TAG_ID_C, t.TAG_NAME_C, t.TAG_COLOR_C, t.TAG_IDPARENT_C, count(d.DOC_ID_C) ");
|
|
||||||
sb.append(" from T_TAG t ");
|
|
||||||
sb.append(" left join T_DOCUMENT_TAG dt on t.TAG_ID_C = dt.DOT_IDTAG_C and dt.DOT_DELETEDATE_D is null ");
|
|
||||||
sb.append(" left join T_DOCUMENT d on d.DOC_ID_C = dt.DOT_IDDOCUMENT_C and d.DOC_DELETEDATE_D is null and d.DOC_IDUSER_C = :userId ");
|
|
||||||
sb.append(" where t.TAG_IDUSER_C = :userId and t.TAG_DELETEDATE_D is null ");
|
|
||||||
sb.append(" group by t.TAG_ID_C ");
|
|
||||||
sb.append(" order by t.TAG_NAME_C ");
|
|
||||||
|
|
||||||
// Perform the query
|
|
||||||
Query q = em.createNativeQuery(sb.toString());
|
|
||||||
q.setParameter("userId", userId);
|
|
||||||
List<Object[]> l = q.getResultList();
|
|
||||||
|
|
||||||
// Assemble results
|
|
||||||
List<TagStatDto> tagStatDtoList = new ArrayList<TagStatDto>();
|
|
||||||
for (Object[] o : l) {
|
|
||||||
int i = 0;
|
|
||||||
TagStatDto tagDto = new TagStatDto();
|
|
||||||
tagDto.setId((String) o[i++]);
|
|
||||||
tagDto.setName((String) o[i++]);
|
|
||||||
tagDto.setColor((String) o[i++]);
|
|
||||||
tagDto.setParentId((String) o[i++]);
|
|
||||||
tagDto.setCount(((Number) o[i++]).intValue());
|
|
||||||
tagStatDtoList.add(tagDto);
|
|
||||||
}
|
|
||||||
return tagStatDtoList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new tag.
|
* Creates a new tag.
|
||||||
*
|
*
|
||||||
* @param tag Tag
|
* @param tag Tag
|
||||||
* @param userId User ID
|
* @param userId User ID
|
||||||
* @return New ID
|
* @return New ID
|
||||||
* @throws Exception
|
|
||||||
*/
|
*/
|
||||||
public String create(Tag tag, String userId) {
|
public String create(Tag tag, String userId) {
|
||||||
// Create the UUID
|
// Create the UUID
|
||||||
@ -189,44 +106,6 @@ public class TagDao {
|
|||||||
return tag.getId();
|
return tag.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a tag by name.
|
|
||||||
*
|
|
||||||
* @param userId User ID
|
|
||||||
* @param name Name
|
|
||||||
* @return Tag
|
|
||||||
*/
|
|
||||||
public Tag getByName(String userId, String name) {
|
|
||||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
|
||||||
Query q = em.createQuery("select t from Tag t where t.name = :name and t.userId = :userId and t.deleteDate is null");
|
|
||||||
q.setParameter("userId", userId);
|
|
||||||
q.setParameter("name", name);
|
|
||||||
try {
|
|
||||||
return (Tag) q.getSingleResult();
|
|
||||||
} catch (NoResultException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a tag by ID.
|
|
||||||
*
|
|
||||||
* @param userId User ID
|
|
||||||
* @param tagId Tag ID
|
|
||||||
* @return Tag
|
|
||||||
*/
|
|
||||||
public Tag getByTagId(String userId, String tagId) {
|
|
||||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
|
||||||
Query q = em.createQuery("select t from Tag t where t.id = :tagId and t.userId = :userId and t.deleteDate is null");
|
|
||||||
q.setParameter("userId", userId);
|
|
||||||
q.setParameter("tagId", tagId);
|
|
||||||
try {
|
|
||||||
return (Tag) q.getSingleResult();
|
|
||||||
} catch (NoResultException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a tag.
|
* Deletes a tag.
|
||||||
*
|
*
|
||||||
@ -251,25 +130,15 @@ public class TagDao {
|
|||||||
q.setParameter("tagId", tagId);
|
q.setParameter("tagId", tagId);
|
||||||
q.executeUpdate();
|
q.executeUpdate();
|
||||||
|
|
||||||
|
q = em.createQuery("update Acl a set a.deleteDate = :dateNow where a.sourceId = :tagId and a.deleteDate is null");
|
||||||
|
q.setParameter("tagId", tagId);
|
||||||
|
q.setParameter("dateNow", dateNow);
|
||||||
|
q.executeUpdate();
|
||||||
|
|
||||||
// Create audit log
|
// Create audit log
|
||||||
AuditLogUtil.create(tagDb, AuditLogType.DELETE, userId);
|
AuditLogUtil.create(tagDb, AuditLogType.DELETE, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Search tags by name.
|
|
||||||
*
|
|
||||||
* @param name Tag name
|
|
||||||
* @return List of found tags
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public List<Tag> findByName(String userId, String name) {
|
|
||||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
|
||||||
Query q = em.createQuery("select t from Tag t where t.name like :name and t.userId = :userId and t.deleteDate is null");
|
|
||||||
q.setParameter("userId", userId);
|
|
||||||
q.setParameter("name", "%" + name + "%");
|
|
||||||
return q.getResultList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update a tag.
|
* Update a tag.
|
||||||
*
|
*
|
||||||
@ -295,5 +164,72 @@ public class TagDao {
|
|||||||
|
|
||||||
return tagFromDb;
|
return tagFromDb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of all tags.
|
||||||
|
*
|
||||||
|
* @param criteria Search criteria
|
||||||
|
* @param sortCriteria Sort criteria
|
||||||
|
* @return List of groups
|
||||||
|
*/
|
||||||
|
public List<TagDto> findByCriteria(TagCriteria criteria, SortCriteria sortCriteria) {
|
||||||
|
Map<String, Object> parameterMap = new HashMap<>();
|
||||||
|
List<String> criteriaList = new ArrayList<>();
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder("select distinct t.TAG_ID_C as c0, t.TAG_NAME_C as c1, t.TAG_COLOR_C as c2, t.TAG_IDPARENT_C as c3, u.USE_USERNAME_C as c4 ");
|
||||||
|
sb.append(" from T_TAG t ");
|
||||||
|
sb.append(" join T_USER u on t.TAG_IDUSER_C = u.USE_ID_C ");
|
||||||
|
|
||||||
|
// Add search criterias
|
||||||
|
if (criteria.getId() != null) {
|
||||||
|
criteriaList.add("t.TAG_ID_C = :id");
|
||||||
|
parameterMap.put("id", criteria.getId());
|
||||||
|
}
|
||||||
|
if (criteria.getTargetIdList() != null) {
|
||||||
|
sb.append(" left join T_ACL a on a.ACL_TARGETID_C in (:targetIdList) and a.ACL_SOURCEID_C = t.TAG_ID_C and a.ACL_PERM_C = 'READ' and a.ACL_DELETEDATE_D is null ");
|
||||||
|
criteriaList.add("a.ACL_ID_C is not null");
|
||||||
|
parameterMap.put("targetIdList", criteria.getTargetIdList());
|
||||||
|
}
|
||||||
|
if (criteria.getDocumentId() != null) {
|
||||||
|
sb.append(" join T_DOCUMENT_TAG dt on dt.DOT_IDTAG_C = t.TAG_ID_C and dt.DOT_DELETEDATE_D is null ");
|
||||||
|
criteriaList.add("dt.DOT_IDDOCUMENT_C = :documentId");
|
||||||
|
parameterMap.put("documentId", criteria.getDocumentId());
|
||||||
|
}
|
||||||
|
if (criteria.getName() != null) {
|
||||||
|
criteriaList.add("t.TAG_NAME_C = :name");
|
||||||
|
parameterMap.put("name", criteria.getName());
|
||||||
|
}
|
||||||
|
if (criteria.getNameLike() != null) {
|
||||||
|
criteriaList.add("t.TAG_NAME_C like :nameLike");
|
||||||
|
parameterMap.put("nameLike", "%" + criteria.getNameLike() + "%");
|
||||||
|
}
|
||||||
|
|
||||||
|
criteriaList.add("t.TAG_DELETEDATE_D is null");
|
||||||
|
|
||||||
|
if (!criteriaList.isEmpty()) {
|
||||||
|
sb.append(" where ");
|
||||||
|
sb.append(Joiner.on(" and ").join(criteriaList));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform the search
|
||||||
|
QueryParam queryParam = QueryUtil.getSortedQueryParam(new QueryParam(sb.toString(), parameterMap), sortCriteria);
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<Object[]> l = QueryUtil.getNativeQuery(queryParam).getResultList();
|
||||||
|
|
||||||
|
// Assemble results
|
||||||
|
List<TagDto> tagDtoList = new ArrayList<>();
|
||||||
|
for (Object[] o : l) {
|
||||||
|
int i = 0;
|
||||||
|
TagDto tagDto = new TagDto()
|
||||||
|
.setId((String) o[i++])
|
||||||
|
.setName((String) o[i++])
|
||||||
|
.setColor((String) o[i++])
|
||||||
|
.setParentId((String) o[i++])
|
||||||
|
.setCreator((String) o[i]);
|
||||||
|
tagDtoList.add(tagDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tagDtoList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,23 +188,6 @@ public class UserDao {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets an active user by its password recovery token.
|
|
||||||
*
|
|
||||||
* @param passwordResetKey Password recovery token
|
|
||||||
* @return User
|
|
||||||
*/
|
|
||||||
public User getActiveByPasswordResetKey(String passwordResetKey) {
|
|
||||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
|
||||||
try {
|
|
||||||
Query q = em.createQuery("select u from User u where u.passwordResetKey = :passwordResetKey and u.deleteDate is null");
|
|
||||||
q.setParameter("passwordResetKey", passwordResetKey);
|
|
||||||
return (User) q.getSingleResult();
|
|
||||||
} catch (NoResultException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a user.
|
* Deletes a user.
|
||||||
*
|
*
|
||||||
@ -258,7 +241,7 @@ public class UserDao {
|
|||||||
* @param password Clear password
|
* @param password Clear password
|
||||||
* @return Hashed password
|
* @return Hashed password
|
||||||
*/
|
*/
|
||||||
protected String hashPassword(String password) {
|
private String hashPassword(String password) {
|
||||||
return BCrypt.hashpw(password, BCrypt.gensalt());
|
return BCrypt.hashpw(password, BCrypt.gensalt());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,8 +253,8 @@ public class UserDao {
|
|||||||
* @return List of users
|
* @return List of users
|
||||||
*/
|
*/
|
||||||
public List<UserDto> findByCriteria(UserCriteria criteria, SortCriteria sortCriteria) {
|
public List<UserDto> findByCriteria(UserCriteria criteria, SortCriteria sortCriteria) {
|
||||||
Map<String, Object> parameterMap = new HashMap<String, Object>();
|
Map<String, Object> parameterMap = new HashMap<>();
|
||||||
List<String> criteriaList = new ArrayList<String>();
|
List<String> criteriaList = new ArrayList<>();
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder("select u.USE_ID_C as c0, u.USE_USERNAME_C as c1, u.USE_EMAIL_C as c2, u.USE_CREATEDATE_D as c3, u.USE_STORAGECURRENT_N as c4, u.USE_STORAGEQUOTA_N as c5");
|
StringBuilder sb = new StringBuilder("select u.USE_ID_C as c0, u.USE_USERNAME_C as c1, u.USE_EMAIL_C as c2, u.USE_CREATEDATE_D as c3, u.USE_STORAGECURRENT_N as c4, u.USE_STORAGEQUOTA_N as c5");
|
||||||
sb.append(" from T_USER u ");
|
sb.append(" from T_USER u ");
|
||||||
@ -300,7 +283,7 @@ public class UserDao {
|
|||||||
List<Object[]> l = QueryUtil.getNativeQuery(queryParam).getResultList();
|
List<Object[]> l = QueryUtil.getNativeQuery(queryParam).getResultList();
|
||||||
|
|
||||||
// Assemble results
|
// Assemble results
|
||||||
List<UserDto> userDtoList = new ArrayList<UserDto>();
|
List<UserDto> userDtoList = new ArrayList<>();
|
||||||
for (Object[] o : l) {
|
for (Object[] o : l) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
UserDto userDto = new UserDto();
|
UserDto userDto = new UserDto();
|
||||||
@ -309,7 +292,7 @@ public class UserDao {
|
|||||||
userDto.setEmail((String) o[i++]);
|
userDto.setEmail((String) o[i++]);
|
||||||
userDto.setCreateTimestamp(((Timestamp) o[i++]).getTime());
|
userDto.setCreateTimestamp(((Timestamp) o[i++]).getTime());
|
||||||
userDto.setStorageCurrent(((Number) o[i++]).longValue());
|
userDto.setStorageCurrent(((Number) o[i++]).longValue());
|
||||||
userDto.setStorageQuota(((Number) o[i++]).longValue());
|
userDto.setStorageQuota(((Number) o[i]).longValue());
|
||||||
userDtoList.add(userDto);
|
userDtoList.add(userDto);
|
||||||
}
|
}
|
||||||
return userDtoList;
|
return userDtoList;
|
||||||
|
@ -0,0 +1,80 @@
|
|||||||
|
package com.sismics.docs.core.dao.jpa.criteria;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tag criteria.
|
||||||
|
*
|
||||||
|
* @author bgamard
|
||||||
|
*/
|
||||||
|
public class TagCriteria {
|
||||||
|
/**
|
||||||
|
* Tag ID.
|
||||||
|
*/
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ACL target ID list.
|
||||||
|
*/
|
||||||
|
private List<String> targetIdList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Document ID.
|
||||||
|
*/
|
||||||
|
private String documentId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tag name.
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Approximate tag name.
|
||||||
|
*/
|
||||||
|
private String nameLike;
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TagCriteria setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getTargetIdList() {
|
||||||
|
return targetIdList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TagCriteria setTargetIdList(List<String> targetIdList) {
|
||||||
|
this.targetIdList = targetIdList;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDocumentId() {
|
||||||
|
return documentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TagCriteria setDocumentId(String documentId) {
|
||||||
|
this.documentId = documentId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TagCriteria setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNameLike() {
|
||||||
|
return nameLike;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TagCriteria setNameLike(String nameLike) {
|
||||||
|
this.nameLike = nameLike;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -26,35 +26,53 @@ public class TagDto {
|
|||||||
*/
|
*/
|
||||||
private String parentId;
|
private String parentId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creator.
|
||||||
|
*/
|
||||||
|
private String creator;
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setId(String id) {
|
public TagDto setId(String id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String name) {
|
public TagDto setName(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getColor() {
|
public String getColor() {
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setColor(String color) {
|
public TagDto setColor(String color) {
|
||||||
this.color = color;
|
this.color = color;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getParentId() {
|
public String getParentId() {
|
||||||
return parentId;
|
return parentId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setParentId(String parentId) {
|
public TagDto setParentId(String parentId) {
|
||||||
this.parentId = parentId;
|
this.parentId = parentId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCreator() {
|
||||||
|
return creator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TagDto setCreator(String creator) {
|
||||||
|
this.creator = creator;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ public class FileCreatedAsyncListener {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
FileDao fileDao = new FileDao();
|
FileDao fileDao = new FileDao();
|
||||||
if (fileDao.getById(file.getId()) == null) {
|
if (fileDao.getActiveById(file.getId()) == null) {
|
||||||
// The file has been deleted since the text extraction started, ignore the result
|
// The file has been deleted since the text extraction started, ignore the result
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ public class AppContext {
|
|||||||
eventBus = new EventBus();
|
eventBus = new EventBus();
|
||||||
eventBus.register(new DeadEventListener());
|
eventBus.register(new DeadEventListener());
|
||||||
|
|
||||||
asyncExecutorList = new ArrayList<ExecutorService>();
|
asyncExecutorList = new ArrayList<>();
|
||||||
|
|
||||||
asyncEventBus = newAsyncEventBus();
|
asyncEventBus = newAsyncEventBus();
|
||||||
asyncEventBus.register(new FileCreatedAsyncListener());
|
asyncEventBus.register(new FileCreatedAsyncListener());
|
||||||
|
@ -86,6 +86,15 @@ public class DirectoryUtil {
|
|||||||
return getDataSubDirectory("log");
|
return getDataSubDirectory("log");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the theme directory.
|
||||||
|
*
|
||||||
|
* @return Theme directory.
|
||||||
|
*/
|
||||||
|
public static Path getThemeDirectory() {
|
||||||
|
return getDataSubDirectory("theme");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a subdirectory of the base data directory
|
* Returns a subdirectory of the base data directory
|
||||||
*
|
*
|
||||||
|
@ -99,6 +99,10 @@ public class PdfPage implements Closeable {
|
|||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private void drawText(float paragraphWidth, PDFont font, int fontSize, String text, boolean centered) throws IOException {
|
private void drawText(float paragraphWidth, PDFont font, int fontSize, String text, boolean centered) throws IOException {
|
||||||
|
if (text == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
pdContent.setFont(font, fontSize);
|
pdContent.setFont(font, fontSize);
|
||||||
int start = 0;
|
int start = 0;
|
||||||
int end = 0;
|
int end = 0;
|
||||||
|
@ -11,7 +11,7 @@ public class ThreadLocalContext {
|
|||||||
/**
|
/**
|
||||||
* ThreadLocal to store the context.
|
* ThreadLocal to store the context.
|
||||||
*/
|
*/
|
||||||
public static final ThreadLocal<ThreadLocalContext> threadLocalContext = new ThreadLocal<ThreadLocalContext>();
|
private static final ThreadLocal<ThreadLocalContext> threadLocalContext = new ThreadLocal<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entity manager.
|
* Entity manager.
|
||||||
@ -46,15 +46,6 @@ public class ThreadLocalContext {
|
|||||||
threadLocalContext.set(null);
|
threadLocalContext.set(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true only if the entity manager is defined.
|
|
||||||
*
|
|
||||||
* @return Condition
|
|
||||||
*/
|
|
||||||
public boolean isInTransactionalContext() {
|
|
||||||
return entityManager != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Getter of entityManager.
|
* Getter of entityManager.
|
||||||
*
|
*
|
||||||
|
39
docs-core/src/main/java/com/sismics/util/css/Rule.java
Normal file
39
docs-core/src/main/java/com/sismics/util/css/Rule.java
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package com.sismics.util.css;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A CSS rule.
|
||||||
|
*
|
||||||
|
* @author bgamard
|
||||||
|
*/
|
||||||
|
public class Rule {
|
||||||
|
/**
|
||||||
|
* Rule separator.
|
||||||
|
*/
|
||||||
|
private static String SEPARATOR = ": ";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CSS rule property name.
|
||||||
|
*/
|
||||||
|
private String property;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CSS rule value.
|
||||||
|
*/
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new CSS rule.
|
||||||
|
*
|
||||||
|
* @param property Property name
|
||||||
|
* @param value Value
|
||||||
|
*/
|
||||||
|
public Rule(String property, String value) {
|
||||||
|
this.property = property;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return property + SEPARATOR + value;
|
||||||
|
}
|
||||||
|
}
|
56
docs-core/src/main/java/com/sismics/util/css/Selector.java
Normal file
56
docs-core/src/main/java/com/sismics/util/css/Selector.java
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package com.sismics.util.css;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A CSS selector.
|
||||||
|
*
|
||||||
|
* @author bgamard
|
||||||
|
*/
|
||||||
|
public class Selector {
|
||||||
|
/**
|
||||||
|
* Selector name.
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rules in this selector.
|
||||||
|
*/
|
||||||
|
private List<Rule> ruleList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new CSS selector.
|
||||||
|
*
|
||||||
|
* @param name Selector name
|
||||||
|
*/
|
||||||
|
public Selector(String name) {
|
||||||
|
this.name = name;
|
||||||
|
ruleList = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a CSS rule.
|
||||||
|
*
|
||||||
|
* @param property Property name
|
||||||
|
* @param value Value
|
||||||
|
* @return CSS selector
|
||||||
|
*/
|
||||||
|
public Selector rule(String property, String value) {
|
||||||
|
ruleList.add(new Rule(property, value));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder(name);
|
||||||
|
sb.append(" {\n");
|
||||||
|
for (Rule rule : ruleList) {
|
||||||
|
sb.append(" ");
|
||||||
|
sb.append(rule);
|
||||||
|
sb.append(";\n");
|
||||||
|
}
|
||||||
|
sb.append("}\n");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -37,17 +37,15 @@ import com.sismics.util.ResourceUtil;
|
|||||||
*
|
*
|
||||||
* @author jtremeaux
|
* @author jtremeaux
|
||||||
*/
|
*/
|
||||||
public abstract class DbOpenHelper {
|
abstract class DbOpenHelper {
|
||||||
/**
|
/**
|
||||||
* Logger.
|
* Logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger log = LoggerFactory.getLogger(DbOpenHelper.class);
|
private static final Logger log = LoggerFactory.getLogger(DbOpenHelper.class);
|
||||||
|
|
||||||
private final SqlStatementLogger sqlStatementLogger;
|
|
||||||
|
|
||||||
private final JdbcConnectionAccess jdbcConnectionAccess;
|
private final JdbcConnectionAccess jdbcConnectionAccess;
|
||||||
|
|
||||||
private final List<Exception> exceptions = new ArrayList<Exception>();
|
private final List<Exception> exceptions = new ArrayList<>();
|
||||||
|
|
||||||
private Formatter formatter;
|
private Formatter formatter;
|
||||||
|
|
||||||
@ -55,9 +53,9 @@ public abstract class DbOpenHelper {
|
|||||||
|
|
||||||
private Statement stmt;
|
private Statement stmt;
|
||||||
|
|
||||||
public DbOpenHelper(ServiceRegistry serviceRegistry) throws HibernateException {
|
DbOpenHelper(ServiceRegistry serviceRegistry) throws HibernateException {
|
||||||
final JdbcServices jdbcServices = serviceRegistry.getService(JdbcServices.class);
|
final JdbcServices jdbcServices = serviceRegistry.getService(JdbcServices.class);
|
||||||
sqlStatementLogger = jdbcServices.getSqlStatementLogger();
|
SqlStatementLogger sqlStatementLogger = jdbcServices.getSqlStatementLogger();
|
||||||
jdbcConnectionAccess = jdbcServices.getBootstrapJdbcConnectionAccess();
|
jdbcConnectionAccess = jdbcServices.getBootstrapJdbcConnectionAccess();
|
||||||
formatter = (sqlStatementLogger.isFormat() ? FormatStyle.DDL : FormatStyle.NONE).getFormatter();
|
formatter = (sqlStatementLogger.isFormat() ? FormatStyle.DDL : FormatStyle.NONE).getFormatter();
|
||||||
}
|
}
|
||||||
@ -66,7 +64,6 @@ public abstract class DbOpenHelper {
|
|||||||
log.info("Opening database and executing incremental updates");
|
log.info("Opening database and executing incremental updates");
|
||||||
|
|
||||||
Connection connection = null;
|
Connection connection = null;
|
||||||
Writer outputFileWriter = null;
|
|
||||||
|
|
||||||
exceptions.clear();
|
exceptions.clear();
|
||||||
|
|
||||||
@ -130,14 +127,6 @@ public abstract class DbOpenHelper {
|
|||||||
exceptions.add(e);
|
exceptions.add(e);
|
||||||
log.error("Unable to close connection", e);
|
log.error("Unable to close connection", e);
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
if (outputFileWriter != null) {
|
|
||||||
outputFileWriter.close();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
exceptions.add(e);
|
|
||||||
log.error("Unable to close connection", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +136,7 @@ public abstract class DbOpenHelper {
|
|||||||
* @param version Version number
|
* @param version Version number
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
protected void executeAllScript(final int version) throws Exception {
|
void executeAllScript(final int version) throws Exception {
|
||||||
List<String> fileNameList = ResourceUtil.list(getClass(), "/db/update/", new FilenameFilter() {
|
List<String> fileNameList = ResourceUtil.list(getClass(), "/db/update/", new FilenameFilter() {
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(File dir, String name) {
|
public boolean accept(File dir, String name) {
|
||||||
@ -173,7 +162,7 @@ public abstract class DbOpenHelper {
|
|||||||
* @throws IOException
|
* @throws IOException
|
||||||
* @throws SQLException
|
* @throws SQLException
|
||||||
*/
|
*/
|
||||||
protected void executeScript(InputStream inputScript) throws IOException, SQLException {
|
void executeScript(InputStream inputScript) throws IOException, SQLException {
|
||||||
List<String> lines = CharStreams.readLines(new InputStreamReader(inputScript));
|
List<String> lines = CharStreams.readLines(new InputStreamReader(inputScript));
|
||||||
|
|
||||||
for (String sql : lines) {
|
for (String sql : lines) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.sismics.util.mime;
|
package com.sismics.util.mime;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
||||||
@ -21,16 +22,16 @@ public class MimeTypeUtil {
|
|||||||
*
|
*
|
||||||
* @param is Stream to inspect
|
* @param is Stream to inspect
|
||||||
* @return MIME type
|
* @return MIME type
|
||||||
* @throws Exception
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public static String guessMimeType(InputStream is) throws Exception {
|
public static String guessMimeType(InputStream is) throws IOException {
|
||||||
byte[] headerBytes = new byte[64];
|
byte[] headerBytes = new byte[64];
|
||||||
is.mark(headerBytes.length);
|
is.mark(headerBytes.length);
|
||||||
int readCount = is.read(headerBytes);
|
int readCount = is.read(headerBytes);
|
||||||
is.reset();
|
is.reset();
|
||||||
|
|
||||||
if (readCount <= 0) {
|
if (readCount <= 0) {
|
||||||
throw new Exception("Cannot read input file");
|
throw new IOException("Cannot read input file");
|
||||||
}
|
}
|
||||||
|
|
||||||
return guessMimeType(headerBytes);
|
return guessMimeType(headerBytes);
|
||||||
|
@ -98,9 +98,8 @@ public class TestFileUtil {
|
|||||||
file4.setId("document_odt");
|
file4.setId("document_odt");
|
||||||
file4.setMimeType(MimeType.OPEN_DOCUMENT_TEXT);
|
file4.setMimeType(MimeType.OPEN_DOCUMENT_TEXT);
|
||||||
|
|
||||||
try (InputStream pdfInputStream = PdfUtil.convertToPdf(documentDto, Lists.newArrayList(file0, file1, file2, file3, file4), true, true, 10)) {
|
InputStream is = PdfUtil.convertToPdf(documentDto, Lists.newArrayList(file0, file1, file2, file3, file4), true, true, 10);
|
||||||
ByteStreams.copy(pdfInputStream, System.out);
|
is.close();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
20
docs-core/src/test/java/com/sismics/util/TestCss.java
Normal file
20
docs-core/src/test/java/com/sismics/util/TestCss.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package com.sismics.util;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.sismics.util.css.Selector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of CSS utilities.
|
||||||
|
*
|
||||||
|
* @author bgamard
|
||||||
|
*/
|
||||||
|
public class TestCss {
|
||||||
|
@Test
|
||||||
|
public void testBuildCss() {
|
||||||
|
Selector selector = new Selector(".test")
|
||||||
|
.rule("background-color", "yellow")
|
||||||
|
.rule("font-family", "Comic Sans");
|
||||||
|
System.out.println(selector);
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,7 @@
|
|||||||
<groupId>com.sismics.docs</groupId>
|
<groupId>com.sismics.docs</groupId>
|
||||||
<artifactId>docs-parent</artifactId>
|
<artifactId>docs-parent</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
<relativePath>../docs-parent</relativePath>
|
<relativePath>..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
@ -27,6 +27,11 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Depenedencies to Docs -->
|
<!-- Depenedencies to Docs -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sismics.docs</groupId>
|
||||||
|
<artifactId>docs-web-common</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.sismics.docs</groupId>
|
<groupId>com.sismics.docs</groupId>
|
||||||
<artifactId>docs-web-common</artifactId>
|
<artifactId>docs-web-common</artifactId>
|
||||||
|
@ -1,36 +1,29 @@
|
|||||||
package com.sismics.docs.stress;
|
package com.sismics.docs.stress;
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
|
||||||
|
|
||||||
import javax.json.JsonObject;
|
|
||||||
import javax.ws.rs.client.Client;
|
|
||||||
import javax.ws.rs.client.ClientBuilder;
|
|
||||||
import javax.ws.rs.client.Entity;
|
|
||||||
import javax.ws.rs.client.Invocation;
|
|
||||||
import javax.ws.rs.client.WebTarget;
|
|
||||||
import javax.ws.rs.core.Form;
|
|
||||||
import javax.ws.rs.core.MediaType;
|
|
||||||
import javax.ws.rs.core.Response.Status;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
|
|
||||||
import org.glassfish.jersey.client.ClientResponse;
|
|
||||||
import org.glassfish.jersey.media.multipart.FormDataMultiPart;
|
|
||||||
import org.glassfish.jersey.media.multipart.MultiPartFeature;
|
|
||||||
import org.glassfish.jersey.media.multipart.file.StreamDataBodyPart;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.google.common.io.Resources;
|
import com.google.common.io.Resources;
|
||||||
import com.sismics.docs.rest.util.ClientUtil;
|
import com.sismics.docs.rest.util.ClientUtil;
|
||||||
import com.sismics.util.filter.TokenBasedSecurityFilter;
|
import com.sismics.util.filter.TokenBasedSecurityFilter;
|
||||||
|
import org.glassfish.jersey.client.ClientResponse;
|
||||||
|
import org.glassfish.jersey.media.multipart.FormDataMultiPart;
|
||||||
|
import org.glassfish.jersey.media.multipart.MultiPartFeature;
|
||||||
|
import org.glassfish.jersey.media.multipart.file.StreamDataBodyPart;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.json.JsonObject;
|
||||||
|
import javax.ws.rs.client.*;
|
||||||
|
import javax.ws.rs.core.Form;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.Response.Status;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stress app for Sismics Docs.
|
* Stress app for Sismics Docs.
|
||||||
@ -47,10 +40,9 @@ public class Main {
|
|||||||
private static final int USER_COUNT = 50;
|
private static final int USER_COUNT = 50;
|
||||||
private static final int DOCUMENT_PER_USER_COUNT = 2000;
|
private static final int DOCUMENT_PER_USER_COUNT = 2000;
|
||||||
private static final int TAG_PER_USER_COUNT = 20;
|
private static final int TAG_PER_USER_COUNT = 20;
|
||||||
private static final int FILE_PER_DOCUMENT_COUNT = 0;
|
private static final int FILE_PER_DOCUMENT_COUNT = 10;
|
||||||
|
|
||||||
private static Client client = ClientBuilder.newClient();
|
private static Client client = ClientBuilder.newClient();
|
||||||
private static ClientUtil clientUtil;
|
|
||||||
|
|
||||||
private static Set<User> userSet = Sets.newHashSet();
|
private static Set<User> userSet = Sets.newHashSet();
|
||||||
|
|
||||||
@ -64,7 +56,7 @@ public class Main {
|
|||||||
log.info("Starting stress test...");
|
log.info("Starting stress test...");
|
||||||
|
|
||||||
WebTarget resource = client.target(API_URL);
|
WebTarget resource = client.target(API_URL);
|
||||||
clientUtil = new ClientUtil(resource);
|
ClientUtil clientUtil = new ClientUtil(resource);
|
||||||
|
|
||||||
// Create users
|
// Create users
|
||||||
for (int i = 0; i < USER_COUNT; i++) {
|
for (int i = 0; i < USER_COUNT; i++) {
|
||||||
@ -131,11 +123,11 @@ public class Main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class User {
|
private static class User {
|
||||||
public String username;
|
String username;
|
||||||
public List<String> tagList = Lists.newArrayList();
|
List<String> tagList = Lists.newArrayList();
|
||||||
public String authToken;
|
String authToken;
|
||||||
|
|
||||||
public User(String username, String authToken) {
|
User(String username, String authToken) {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.authToken = authToken;
|
this.authToken = authToken;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.sismics.docs</groupId>
|
<groupId>com.sismics.docs</groupId>
|
||||||
<artifactId>docs-parent</artifactId>
|
<artifactId>docs-parent</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
<relativePath>../docs-parent</relativePath>
|
<relativePath>..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
package com.sismics.rest.util;
|
||||||
|
|
||||||
|
import com.sismics.docs.core.constant.PermType;
|
||||||
|
import com.sismics.docs.core.dao.jpa.AclDao;
|
||||||
|
import com.sismics.docs.core.dao.jpa.dto.AclDto;
|
||||||
|
|
||||||
|
import javax.json.Json;
|
||||||
|
import javax.json.JsonArrayBuilder;
|
||||||
|
import javax.json.JsonObjectBuilder;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acl utilities.
|
||||||
|
*
|
||||||
|
* @author bgamard
|
||||||
|
*/
|
||||||
|
public class AclUtil {
|
||||||
|
/**
|
||||||
|
* Add ACLs to a JSON response.
|
||||||
|
*
|
||||||
|
* @param json JSON
|
||||||
|
* @param sourceId Source ID
|
||||||
|
* @param targetIdList List of target ID
|
||||||
|
*/
|
||||||
|
public static void addAcls(JsonObjectBuilder json, String sourceId, List<String> targetIdList) {
|
||||||
|
AclDao aclDao = new AclDao();
|
||||||
|
List<AclDto> aclDtoList = aclDao.getBySourceId(sourceId);
|
||||||
|
JsonArrayBuilder aclList = Json.createArrayBuilder();
|
||||||
|
for (AclDto aclDto : aclDtoList) {
|
||||||
|
aclList.add(Json.createObjectBuilder()
|
||||||
|
.add("perm", aclDto.getPerm().name())
|
||||||
|
.add("id", aclDto.getTargetId())
|
||||||
|
.add("name", JsonUtil.nullable(aclDto.getTargetName()))
|
||||||
|
.add("type", aclDto.getTargetType()));
|
||||||
|
}
|
||||||
|
json.add("acls", aclList)
|
||||||
|
.add("writable", aclDao.checkPermission(sourceId, PermType.WRITE, targetIdList));
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,6 @@ import javax.json.JsonValue;
|
|||||||
* @author bgamard
|
* @author bgamard
|
||||||
*/
|
*/
|
||||||
public class JsonUtil {
|
public class JsonUtil {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a JsonValue from a String.
|
* Returns a JsonValue from a String.
|
||||||
*
|
*
|
||||||
|
@ -108,10 +108,9 @@ public class ValidationUtil {
|
|||||||
* @param s String to validate
|
* @param s String to validate
|
||||||
* @param name Name of the parameter
|
* @param name Name of the parameter
|
||||||
* @param nullable True if the string can be empty or null
|
* @param nullable True if the string can be empty or null
|
||||||
* @throws JSONException
|
|
||||||
*/
|
*/
|
||||||
public static void validateHexColor(String s, String name, boolean nullable) throws ClientException {
|
public static void validateHexColor(String s, String name, boolean nullable) throws ClientException {
|
||||||
ValidationUtil.validateLength(s, "name", 7, 7, nullable);
|
ValidationUtil.validateLength(s, name, 7, 7, nullable);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -80,7 +80,7 @@ public class RequestContextFilter implements Filter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
|
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
|
||||||
EntityManager em = null;
|
EntityManager em;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
em = EMF.get().createEntityManager();
|
em = EMF.get().createEntityManager();
|
||||||
|
@ -30,7 +30,7 @@ public abstract class BaseJerseyTest extends JerseyTest {
|
|||||||
/**
|
/**
|
||||||
* Test HTTP server.
|
* Test HTTP server.
|
||||||
*/
|
*/
|
||||||
protected HttpServer httpServer;
|
private HttpServer httpServer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class for the REST client.
|
* Utility class for the REST client.
|
||||||
@ -45,7 +45,11 @@ public abstract class BaseJerseyTest extends JerseyTest {
|
|||||||
@Override
|
@Override
|
||||||
protected Application configure() {
|
protected Application configure() {
|
||||||
enable(TestProperties.LOG_TRAFFIC);
|
enable(TestProperties.LOG_TRAFFIC);
|
||||||
|
String travisEnv = System.getenv("TRAVIS");
|
||||||
|
if (travisEnv == null || !travisEnv.equals("true")) {
|
||||||
|
// Travis don't like entity dumped in the logs
|
||||||
enable(TestProperties.DUMP_ENTITY);
|
enable(TestProperties.DUMP_ENTITY);
|
||||||
|
}
|
||||||
return new Application();
|
return new Application();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<groupId>com.sismics.docs</groupId>
|
<groupId>com.sismics.docs</groupId>
|
||||||
<artifactId>docs-parent</artifactId>
|
<artifactId>docs-parent</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
<relativePath>../docs-parent</relativePath>
|
<relativePath>..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
@ -1,40 +1,27 @@
|
|||||||
package com.sismics.docs.rest.resource;
|
package com.sismics.docs.rest.resource;
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.json.Json;
|
|
||||||
import javax.json.JsonArrayBuilder;
|
|
||||||
import javax.json.JsonObjectBuilder;
|
|
||||||
import javax.ws.rs.DELETE;
|
|
||||||
import javax.ws.rs.FormParam;
|
|
||||||
import javax.ws.rs.GET;
|
|
||||||
import javax.ws.rs.PUT;
|
|
||||||
import javax.ws.rs.Path;
|
|
||||||
import javax.ws.rs.PathParam;
|
|
||||||
import javax.ws.rs.QueryParam;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.sismics.docs.core.constant.AclTargetType;
|
import com.sismics.docs.core.constant.AclTargetType;
|
||||||
import com.sismics.docs.core.constant.PermType;
|
import com.sismics.docs.core.constant.PermType;
|
||||||
import com.sismics.docs.core.dao.jpa.AclDao;
|
import com.sismics.docs.core.dao.jpa.*;
|
||||||
import com.sismics.docs.core.dao.jpa.DocumentDao;
|
|
||||||
import com.sismics.docs.core.dao.jpa.GroupDao;
|
|
||||||
import com.sismics.docs.core.dao.jpa.UserDao;
|
|
||||||
import com.sismics.docs.core.dao.jpa.criteria.GroupCriteria;
|
import com.sismics.docs.core.dao.jpa.criteria.GroupCriteria;
|
||||||
import com.sismics.docs.core.dao.jpa.criteria.UserCriteria;
|
import com.sismics.docs.core.dao.jpa.criteria.UserCriteria;
|
||||||
import com.sismics.docs.core.dao.jpa.dto.GroupDto;
|
import com.sismics.docs.core.dao.jpa.dto.GroupDto;
|
||||||
import com.sismics.docs.core.dao.jpa.dto.UserDto;
|
import com.sismics.docs.core.dao.jpa.dto.UserDto;
|
||||||
import com.sismics.docs.core.model.jpa.Acl;
|
import com.sismics.docs.core.model.jpa.*;
|
||||||
import com.sismics.docs.core.model.jpa.Document;
|
|
||||||
import com.sismics.docs.core.model.jpa.Group;
|
|
||||||
import com.sismics.docs.core.model.jpa.User;
|
|
||||||
import com.sismics.docs.core.util.jpa.SortCriteria;
|
import com.sismics.docs.core.util.jpa.SortCriteria;
|
||||||
import com.sismics.rest.exception.ClientException;
|
import com.sismics.rest.exception.ClientException;
|
||||||
import com.sismics.rest.exception.ForbiddenClientException;
|
import com.sismics.rest.exception.ForbiddenClientException;
|
||||||
import com.sismics.rest.util.ValidationUtil;
|
import com.sismics.rest.util.ValidationUtil;
|
||||||
|
|
||||||
|
import javax.json.Json;
|
||||||
|
import javax.json.JsonArrayBuilder;
|
||||||
|
import javax.json.JsonObjectBuilder;
|
||||||
|
import javax.ws.rs.*;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ACL REST resources.
|
* ACL REST resources.
|
||||||
*
|
*
|
||||||
@ -48,7 +35,7 @@ public class AclResource extends BaseResource {
|
|||||||
* @param sourceId Source ID
|
* @param sourceId Source ID
|
||||||
* @param permStr Permission
|
* @param permStr Permission
|
||||||
* @param targetName Target name
|
* @param targetName Target name
|
||||||
* @param type ACL type
|
* @param typeStr ACL type
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
@PUT
|
@PUT
|
||||||
@ -157,6 +144,13 @@ public class AclResource extends BaseResource {
|
|||||||
throw new ClientException("AclError", "Cannot delete base ACL on a document");
|
throw new ClientException("AclError", "Cannot delete base ACL on a document");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cannot delete R/W on a source tag if the target is the creator
|
||||||
|
TagDao tagDao = new TagDao();
|
||||||
|
Tag tag = tagDao.getById(sourceId);
|
||||||
|
if (tag != null && tag.getUserId().equals(targetId)) {
|
||||||
|
throw new ClientException("AclError", "Cannot delete base ACL on a tag");
|
||||||
|
}
|
||||||
|
|
||||||
// Delete the ACL
|
// Delete the ACL
|
||||||
aclDao.delete(sourceId, perm, targetId, principal.getId());
|
aclDao.delete(sourceId, perm, targetId, principal.getId());
|
||||||
|
|
||||||
|
@ -20,6 +20,13 @@ import javax.ws.rs.Path;
|
|||||||
import javax.ws.rs.QueryParam;
|
import javax.ws.rs.QueryParam;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import com.sismics.docs.core.constant.PermType;
|
||||||
|
import com.sismics.docs.core.dao.jpa.AclDao;
|
||||||
|
import com.sismics.docs.core.dao.jpa.TagDao;
|
||||||
|
import com.sismics.docs.core.dao.jpa.criteria.TagCriteria;
|
||||||
|
import com.sismics.docs.core.dao.jpa.dto.AclDto;
|
||||||
|
import com.sismics.docs.core.dao.jpa.dto.TagDto;
|
||||||
|
import com.sismics.docs.core.model.jpa.Acl;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.log4j.Appender;
|
import org.apache.log4j.Appender;
|
||||||
import org.apache.log4j.Level;
|
import org.apache.log4j.Level;
|
||||||
@ -284,12 +291,12 @@ public class AppResource extends BaseResource {
|
|||||||
Map<String, User> userMap = new HashMap<>();
|
Map<String, User> userMap = new HashMap<>();
|
||||||
for (File file : fileList) {
|
for (File file : fileList) {
|
||||||
java.nio.file.Path storedFile = DirectoryUtil.getStorageDirectory().resolve(file.getId());
|
java.nio.file.Path storedFile = DirectoryUtil.getStorageDirectory().resolve(file.getId());
|
||||||
User user = null;
|
User user;
|
||||||
if (userMap.containsKey(file.getUserId())) {
|
if (userMap.containsKey(file.getUserId())) {
|
||||||
user = userMap.get(file.getUserId());
|
user = userMap.get(file.getUserId());
|
||||||
} else {
|
} else {
|
||||||
user = userDao.getById(file.getUserId());
|
user = userDao.getById(file.getUserId());
|
||||||
user.setStorageCurrent(0l);
|
user.setStorageCurrent(0L);
|
||||||
userMap.put(user.getId(), user);
|
userMap.put(user.getId(), user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,4 +319,49 @@ public class AppResource extends BaseResource {
|
|||||||
.add("status", "ok");
|
.add("status", "ok");
|
||||||
return Response.ok().entity(response.build()).build();
|
return Response.ok().entity(response.build()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add base ACLs to tags.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
@POST
|
||||||
|
@Path("batch/tag_acls")
|
||||||
|
public Response batchTagAcls() {
|
||||||
|
if (!authenticate()) {
|
||||||
|
throw new ForbiddenClientException();
|
||||||
|
}
|
||||||
|
checkBaseFunction(BaseFunction.ADMIN);
|
||||||
|
|
||||||
|
// Get all tags
|
||||||
|
TagDao tagDao = new TagDao();
|
||||||
|
List<TagDto> tagDtoList = tagDao.findByCriteria(new TagCriteria(), null);
|
||||||
|
|
||||||
|
// Add READ and WRITE ACLs
|
||||||
|
for (TagDto tagDto : tagDtoList) {
|
||||||
|
AclDao aclDao = new AclDao();
|
||||||
|
List<AclDto> aclDtoList = aclDao.getBySourceId(tagDto.getId());
|
||||||
|
|
||||||
|
if (aclDtoList.size() == 0) {
|
||||||
|
// Create read ACL
|
||||||
|
Acl acl = new Acl();
|
||||||
|
acl.setPerm(PermType.READ);
|
||||||
|
acl.setSourceId(tagDto.getId());
|
||||||
|
acl.setTargetId(principal.getId());
|
||||||
|
aclDao.create(acl, principal.getId());
|
||||||
|
|
||||||
|
// Create write ACL
|
||||||
|
acl = new Acl();
|
||||||
|
acl.setPerm(PermType.WRITE);
|
||||||
|
acl.setSourceId(tagDto.getId());
|
||||||
|
acl.setTargetId(principal.getId());
|
||||||
|
aclDao.create(acl, principal.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always return OK
|
||||||
|
JsonObjectBuilder response = Json.createObjectBuilder()
|
||||||
|
.add("status", "ok");
|
||||||
|
return Response.ok().entity(response.build()).build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,5 @@
|
|||||||
package com.sismics.docs.rest.resource;
|
package com.sismics.docs.rest.resource;
|
||||||
|
|
||||||
import javax.json.Json;
|
|
||||||
import javax.json.JsonArrayBuilder;
|
|
||||||
import javax.json.JsonObjectBuilder;
|
|
||||||
import javax.ws.rs.GET;
|
|
||||||
import javax.ws.rs.Path;
|
|
||||||
import javax.ws.rs.QueryParam;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import javax.ws.rs.core.Response.Status;
|
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.sismics.docs.core.constant.PermType;
|
import com.sismics.docs.core.constant.PermType;
|
||||||
import com.sismics.docs.core.dao.jpa.AclDao;
|
import com.sismics.docs.core.dao.jpa.AclDao;
|
||||||
@ -21,6 +12,15 @@ import com.sismics.docs.core.util.jpa.SortCriteria;
|
|||||||
import com.sismics.rest.exception.ForbiddenClientException;
|
import com.sismics.rest.exception.ForbiddenClientException;
|
||||||
import com.sismics.rest.util.JsonUtil;
|
import com.sismics.rest.util.JsonUtil;
|
||||||
|
|
||||||
|
import javax.json.Json;
|
||||||
|
import javax.json.JsonArrayBuilder;
|
||||||
|
import javax.json.JsonObjectBuilder;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.NotFoundException;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Audit log REST resources.
|
* Audit log REST resources.
|
||||||
*
|
*
|
||||||
@ -50,7 +50,7 @@ public class AuditLogResource extends BaseResource {
|
|||||||
// Check ACL on the document
|
// Check ACL on the document
|
||||||
AclDao aclDao = new AclDao();
|
AclDao aclDao = new AclDao();
|
||||||
if (!aclDao.checkPermission(documentId, PermType.READ, getTargetIdList(null))) {
|
if (!aclDao.checkPermission(documentId, PermType.READ, getTargetIdList(null))) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
criteria.setDocumentId(documentId);
|
criteria.setDocumentId(documentId);
|
||||||
}
|
}
|
||||||
|
@ -57,9 +57,8 @@ public abstract class BaseResource {
|
|||||||
* Checks if the user has a base function. Throw an exception if the check fails.
|
* Checks if the user has a base function. Throw an exception if the check fails.
|
||||||
*
|
*
|
||||||
* @param baseFunction Base function to check
|
* @param baseFunction Base function to check
|
||||||
* @throws JSONException
|
|
||||||
*/
|
*/
|
||||||
protected void checkBaseFunction(BaseFunction baseFunction) {
|
void checkBaseFunction(BaseFunction baseFunction) {
|
||||||
if (!hasBaseFunction(baseFunction)) {
|
if (!hasBaseFunction(baseFunction)) {
|
||||||
throw new ForbiddenClientException();
|
throw new ForbiddenClientException();
|
||||||
}
|
}
|
||||||
@ -70,9 +69,8 @@ public abstract class BaseResource {
|
|||||||
*
|
*
|
||||||
* @param baseFunction Base function to check
|
* @param baseFunction Base function to check
|
||||||
* @return True if the user has the base function
|
* @return True if the user has the base function
|
||||||
* @throws JSONException
|
|
||||||
*/
|
*/
|
||||||
protected boolean hasBaseFunction(BaseFunction baseFunction) {
|
boolean hasBaseFunction(BaseFunction baseFunction) {
|
||||||
if (principal == null || !(principal instanceof UserPrincipal)) {
|
if (principal == null || !(principal instanceof UserPrincipal)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -86,7 +84,7 @@ public abstract class BaseResource {
|
|||||||
* @param shareId Share ID (optional)
|
* @param shareId Share ID (optional)
|
||||||
* @return List of ACL target ID
|
* @return List of ACL target ID
|
||||||
*/
|
*/
|
||||||
protected List<String> getTargetIdList(String shareId) {
|
List<String> getTargetIdList(String shareId) {
|
||||||
List<String> targetIdList = Lists.newArrayList(principal.getGroupIdSet());
|
List<String> targetIdList = Lists.newArrayList(principal.getGroupIdSet());
|
||||||
if (principal.getId() != null) {
|
if (principal.getId() != null) {
|
||||||
targetIdList.add(principal.getId());
|
targetIdList.add(principal.getId());
|
||||||
|
@ -1,29 +1,21 @@
|
|||||||
package com.sismics.docs.rest.resource;
|
package com.sismics.docs.rest.resource;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.json.Json;
|
|
||||||
import javax.json.JsonArrayBuilder;
|
|
||||||
import javax.json.JsonObjectBuilder;
|
|
||||||
import javax.ws.rs.DELETE;
|
|
||||||
import javax.ws.rs.FormParam;
|
|
||||||
import javax.ws.rs.GET;
|
|
||||||
import javax.ws.rs.PUT;
|
|
||||||
import javax.ws.rs.Path;
|
|
||||||
import javax.ws.rs.PathParam;
|
|
||||||
import javax.ws.rs.QueryParam;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import javax.ws.rs.core.Response.Status;
|
|
||||||
|
|
||||||
import com.sismics.docs.core.constant.PermType;
|
import com.sismics.docs.core.constant.PermType;
|
||||||
|
import com.sismics.docs.core.dao.jpa.AclDao;
|
||||||
import com.sismics.docs.core.dao.jpa.CommentDao;
|
import com.sismics.docs.core.dao.jpa.CommentDao;
|
||||||
import com.sismics.docs.core.dao.jpa.DocumentDao;
|
|
||||||
import com.sismics.docs.core.dao.jpa.dto.CommentDto;
|
import com.sismics.docs.core.dao.jpa.dto.CommentDto;
|
||||||
import com.sismics.docs.core.model.jpa.Comment;
|
import com.sismics.docs.core.model.jpa.Comment;
|
||||||
import com.sismics.rest.exception.ForbiddenClientException;
|
import com.sismics.rest.exception.ForbiddenClientException;
|
||||||
import com.sismics.rest.util.ValidationUtil;
|
import com.sismics.rest.util.ValidationUtil;
|
||||||
import com.sismics.util.ImageUtil;
|
import com.sismics.util.ImageUtil;
|
||||||
|
|
||||||
|
import javax.json.Json;
|
||||||
|
import javax.json.JsonArrayBuilder;
|
||||||
|
import javax.json.JsonObjectBuilder;
|
||||||
|
import javax.ws.rs.*;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Comment REST resource.
|
* Comment REST resource.
|
||||||
*
|
*
|
||||||
@ -50,9 +42,9 @@ public class CommentResource extends BaseResource {
|
|||||||
content = ValidationUtil.validateLength(content, "content", 1, 4000, false);
|
content = ValidationUtil.validateLength(content, "content", 1, 4000, false);
|
||||||
|
|
||||||
// Read access on doc gives access to write comments
|
// Read access on doc gives access to write comments
|
||||||
DocumentDao documentDao = new DocumentDao();
|
AclDao aclDao = new AclDao();
|
||||||
if (documentDao.getDocument(documentId, PermType.READ, getTargetIdList(null)) == null) {
|
if (!aclDao.checkPermission(documentId, PermType.READ, getTargetIdList(null))) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the comment
|
// Create the comment
|
||||||
@ -90,15 +82,15 @@ public class CommentResource extends BaseResource {
|
|||||||
CommentDao commentDao = new CommentDao();
|
CommentDao commentDao = new CommentDao();
|
||||||
Comment comment = commentDao.getActiveById(id);
|
Comment comment = commentDao.getActiveById(id);
|
||||||
if (comment == null) {
|
if (comment == null) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the current user owns the comment, skip ACL check
|
// If the current user owns the comment, skip ACL check
|
||||||
if (!comment.getUserId().equals(principal.getId())) {
|
if (!comment.getUserId().equals(principal.getId())) {
|
||||||
// Get the associated document
|
// Get the associated document
|
||||||
DocumentDao documentDao = new DocumentDao();
|
AclDao aclDao = new AclDao();
|
||||||
if (documentDao.getDocument(comment.getDocumentId(), PermType.WRITE, getTargetIdList(null)) == null) {
|
if (!aclDao.checkPermission(comment.getDocumentId(), PermType.WRITE, getTargetIdList(null))) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,9 +116,9 @@ public class CommentResource extends BaseResource {
|
|||||||
authenticate();
|
authenticate();
|
||||||
|
|
||||||
// Read access on doc gives access to read comments
|
// Read access on doc gives access to read comments
|
||||||
DocumentDao documentDao = new DocumentDao();
|
AclDao aclDao = new AclDao();
|
||||||
if (documentDao.getDocument(documentId, PermType.READ, getTargetIdList(shareId)) == null) {
|
if (!aclDao.checkPermission(documentId, PermType.READ, getTargetIdList(shareId))) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assemble results
|
// Assemble results
|
||||||
|
@ -1,56 +1,14 @@
|
|||||||
package com.sismics.docs.rest.resource;
|
package com.sismics.docs.rest.resource;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import javax.json.Json;
|
|
||||||
import javax.json.JsonArrayBuilder;
|
|
||||||
import javax.json.JsonObjectBuilder;
|
|
||||||
import javax.ws.rs.DELETE;
|
|
||||||
import javax.ws.rs.FormParam;
|
|
||||||
import javax.ws.rs.GET;
|
|
||||||
import javax.ws.rs.POST;
|
|
||||||
import javax.ws.rs.PUT;
|
|
||||||
import javax.ws.rs.Path;
|
|
||||||
import javax.ws.rs.PathParam;
|
|
||||||
import javax.ws.rs.QueryParam;
|
|
||||||
import javax.ws.rs.WebApplicationException;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import javax.ws.rs.core.Response.Status;
|
|
||||||
import javax.ws.rs.core.StreamingOutput;
|
|
||||||
|
|
||||||
import org.joda.time.DateTime;
|
|
||||||
import org.joda.time.format.DateTimeFormat;
|
|
||||||
import org.joda.time.format.DateTimeFormatter;
|
|
||||||
import org.joda.time.format.DateTimeFormatterBuilder;
|
|
||||||
import org.joda.time.format.DateTimeParser;
|
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.io.ByteStreams;
|
import com.google.common.io.ByteStreams;
|
||||||
import com.sismics.docs.core.constant.Constants;
|
import com.sismics.docs.core.constant.Constants;
|
||||||
import com.sismics.docs.core.constant.PermType;
|
import com.sismics.docs.core.constant.PermType;
|
||||||
import com.sismics.docs.core.dao.jpa.AclDao;
|
import com.sismics.docs.core.dao.jpa.*;
|
||||||
import com.sismics.docs.core.dao.jpa.ContributorDao;
|
|
||||||
import com.sismics.docs.core.dao.jpa.DocumentDao;
|
|
||||||
import com.sismics.docs.core.dao.jpa.FileDao;
|
|
||||||
import com.sismics.docs.core.dao.jpa.RelationDao;
|
|
||||||
import com.sismics.docs.core.dao.jpa.TagDao;
|
|
||||||
import com.sismics.docs.core.dao.jpa.UserDao;
|
|
||||||
import com.sismics.docs.core.dao.jpa.criteria.DocumentCriteria;
|
import com.sismics.docs.core.dao.jpa.criteria.DocumentCriteria;
|
||||||
import com.sismics.docs.core.dao.jpa.dto.AclDto;
|
import com.sismics.docs.core.dao.jpa.criteria.TagCriteria;
|
||||||
import com.sismics.docs.core.dao.jpa.dto.ContributorDto;
|
import com.sismics.docs.core.dao.jpa.dto.*;
|
||||||
import com.sismics.docs.core.dao.jpa.dto.DocumentDto;
|
|
||||||
import com.sismics.docs.core.dao.jpa.dto.RelationDto;
|
|
||||||
import com.sismics.docs.core.dao.jpa.dto.TagDto;
|
|
||||||
import com.sismics.docs.core.event.DocumentCreatedAsyncEvent;
|
import com.sismics.docs.core.event.DocumentCreatedAsyncEvent;
|
||||||
import com.sismics.docs.core.event.DocumentDeletedAsyncEvent;
|
import com.sismics.docs.core.event.DocumentDeletedAsyncEvent;
|
||||||
import com.sismics.docs.core.event.DocumentUpdatedAsyncEvent;
|
import com.sismics.docs.core.event.DocumentUpdatedAsyncEvent;
|
||||||
@ -59,7 +17,6 @@ import com.sismics.docs.core.model.context.AppContext;
|
|||||||
import com.sismics.docs.core.model.jpa.Acl;
|
import com.sismics.docs.core.model.jpa.Acl;
|
||||||
import com.sismics.docs.core.model.jpa.Document;
|
import com.sismics.docs.core.model.jpa.Document;
|
||||||
import com.sismics.docs.core.model.jpa.File;
|
import com.sismics.docs.core.model.jpa.File;
|
||||||
import com.sismics.docs.core.model.jpa.Tag;
|
|
||||||
import com.sismics.docs.core.model.jpa.User;
|
import com.sismics.docs.core.model.jpa.User;
|
||||||
import com.sismics.docs.core.util.PdfUtil;
|
import com.sismics.docs.core.util.PdfUtil;
|
||||||
import com.sismics.docs.core.util.jpa.PaginatedList;
|
import com.sismics.docs.core.util.jpa.PaginatedList;
|
||||||
@ -68,9 +25,27 @@ import com.sismics.docs.core.util.jpa.SortCriteria;
|
|||||||
import com.sismics.rest.exception.ClientException;
|
import com.sismics.rest.exception.ClientException;
|
||||||
import com.sismics.rest.exception.ForbiddenClientException;
|
import com.sismics.rest.exception.ForbiddenClientException;
|
||||||
import com.sismics.rest.exception.ServerException;
|
import com.sismics.rest.exception.ServerException;
|
||||||
|
import com.sismics.rest.util.AclUtil;
|
||||||
import com.sismics.rest.util.JsonUtil;
|
import com.sismics.rest.util.JsonUtil;
|
||||||
import com.sismics.rest.util.ValidationUtil;
|
import com.sismics.rest.util.ValidationUtil;
|
||||||
import com.sismics.util.mime.MimeType;
|
import com.sismics.util.mime.MimeType;
|
||||||
|
import org.joda.time.DateTime;
|
||||||
|
import org.joda.time.format.DateTimeFormat;
|
||||||
|
import org.joda.time.format.DateTimeFormatter;
|
||||||
|
import org.joda.time.format.DateTimeFormatterBuilder;
|
||||||
|
import org.joda.time.format.DateTimeParser;
|
||||||
|
|
||||||
|
import javax.json.Json;
|
||||||
|
import javax.json.JsonArrayBuilder;
|
||||||
|
import javax.json.JsonObjectBuilder;
|
||||||
|
import javax.ws.rs.*;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import javax.ws.rs.core.StreamingOutput;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Document REST resources.
|
* Document REST resources.
|
||||||
@ -83,6 +58,7 @@ public class DocumentResource extends BaseResource {
|
|||||||
* Returns a document.
|
* Returns a document.
|
||||||
*
|
*
|
||||||
* @param documentId Document ID
|
* @param documentId Document ID
|
||||||
|
* @param shareId Share ID
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
@ -93,10 +69,9 @@ public class DocumentResource extends BaseResource {
|
|||||||
authenticate();
|
authenticate();
|
||||||
|
|
||||||
DocumentDao documentDao = new DocumentDao();
|
DocumentDao documentDao = new DocumentDao();
|
||||||
AclDao aclDao = new AclDao();
|
|
||||||
DocumentDto documentDto = documentDao.getDocument(documentId, PermType.READ, getTargetIdList(shareId));
|
DocumentDto documentDto = documentDao.getDocument(documentId, PermType.READ, getTargetIdList(shareId));
|
||||||
if (documentDto == null) {
|
if (documentDto == null) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonObjectBuilder document = Json.createObjectBuilder()
|
JsonObjectBuilder document = Json.createObjectBuilder()
|
||||||
@ -108,13 +83,18 @@ public class DocumentResource extends BaseResource {
|
|||||||
.add("shared", documentDto.getShared())
|
.add("shared", documentDto.getShared())
|
||||||
.add("file_count", documentDto.getFileCount());
|
.add("file_count", documentDto.getFileCount());
|
||||||
|
|
||||||
|
List<TagDto> tagDtoList = null;
|
||||||
if (principal.isAnonymous()) {
|
if (principal.isAnonymous()) {
|
||||||
// No tags in anonymous mode (sharing)
|
// No tags in anonymous mode (sharing)
|
||||||
document.add("tags", Json.createArrayBuilder());
|
document.add("tags", Json.createArrayBuilder());
|
||||||
} else {
|
} else {
|
||||||
// Add tags added by the current user on this document
|
// Add tags visible by the current user on this document
|
||||||
TagDao tagDao = new TagDao();
|
TagDao tagDao = new TagDao();
|
||||||
List<TagDto> tagDtoList = tagDao.getByDocumentId(documentId, principal.getId());
|
tagDtoList = tagDao.findByCriteria(
|
||||||
|
new TagCriteria()
|
||||||
|
.setTargetIdList(getTargetIdList(shareId))
|
||||||
|
.setDocumentId(documentId),
|
||||||
|
new SortCriteria(1, true));
|
||||||
JsonArrayBuilder tags = Json.createArrayBuilder();
|
JsonArrayBuilder tags = Json.createArrayBuilder();
|
||||||
for (TagDto tagDto : tagDtoList) {
|
for (TagDto tagDto : tagDtoList) {
|
||||||
tags.add(Json.createObjectBuilder()
|
tags.add(Json.createObjectBuilder()
|
||||||
@ -137,26 +117,26 @@ public class DocumentResource extends BaseResource {
|
|||||||
document.add("creator", documentDto.getCreator());
|
document.add("creator", documentDto.getCreator());
|
||||||
|
|
||||||
// Add ACL
|
// Add ACL
|
||||||
List<AclDto> aclDtoList = aclDao.getBySourceId(documentId);
|
AclUtil.addAcls(document, documentId, getTargetIdList(shareId));
|
||||||
|
|
||||||
|
// Add computed ACL
|
||||||
|
if (tagDtoList != null) {
|
||||||
JsonArrayBuilder aclList = Json.createArrayBuilder();
|
JsonArrayBuilder aclList = Json.createArrayBuilder();
|
||||||
boolean writable = false;
|
for (TagDto tagDto : tagDtoList) {
|
||||||
|
AclDao aclDao = new AclDao();
|
||||||
|
List<AclDto> aclDtoList = aclDao.getBySourceId(tagDto.getId());
|
||||||
for (AclDto aclDto : aclDtoList) {
|
for (AclDto aclDto : aclDtoList) {
|
||||||
aclList.add(Json.createObjectBuilder()
|
aclList.add(Json.createObjectBuilder()
|
||||||
.add("perm", aclDto.getPerm().name())
|
.add("perm", aclDto.getPerm().name())
|
||||||
|
.add("source_id", tagDto.getId())
|
||||||
|
.add("source_name", tagDto.getName())
|
||||||
.add("id", aclDto.getTargetId())
|
.add("id", aclDto.getTargetId())
|
||||||
.add("name", JsonUtil.nullable(aclDto.getTargetName()))
|
.add("name", JsonUtil.nullable(aclDto.getTargetName()))
|
||||||
.add("type", aclDto.getTargetType()));
|
.add("type", aclDto.getTargetType()));
|
||||||
|
|
||||||
if (!principal.isAnonymous()
|
|
||||||
&& (aclDto.getTargetId().equals(principal.getId())
|
|
||||||
|| principal.getGroupIdSet().contains(aclDto.getTargetId()))
|
|
||||||
&& aclDto.getPerm() == PermType.WRITE) {
|
|
||||||
// The document is writable for the current user
|
|
||||||
writable = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
document.add("acls", aclList)
|
document.add("inherited_acls", aclList);
|
||||||
.add("writable", writable);
|
}
|
||||||
|
|
||||||
// Add contributors
|
// Add contributors
|
||||||
ContributorDao contributorDao = new ContributorDao();
|
ContributorDao contributorDao = new ContributorDao();
|
||||||
@ -188,6 +168,11 @@ public class DocumentResource extends BaseResource {
|
|||||||
* Export a document to PDF.
|
* Export a document to PDF.
|
||||||
*
|
*
|
||||||
* @param documentId Document ID
|
* @param documentId Document ID
|
||||||
|
* @param shareId Share ID
|
||||||
|
* @param metadata Export metadata
|
||||||
|
* @param comments Export comments
|
||||||
|
* @param fitImageToPage Fit images to page
|
||||||
|
* @param marginStr Margins
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
@ -208,7 +193,7 @@ public class DocumentResource extends BaseResource {
|
|||||||
DocumentDao documentDao = new DocumentDao();
|
DocumentDao documentDao = new DocumentDao();
|
||||||
final DocumentDto documentDto = documentDao.getDocument(documentId, PermType.READ, getTargetIdList(shareId));
|
final DocumentDto documentDto = documentDao.getDocument(documentId, PermType.READ, getTargetIdList(shareId));
|
||||||
if (documentDto == null) {
|
if (documentDto == null) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get files
|
// Get files
|
||||||
@ -231,7 +216,11 @@ public class DocumentResource extends BaseResource {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
} finally {
|
} finally {
|
||||||
|
try {
|
||||||
outputStream.close();
|
outputStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -247,6 +236,9 @@ public class DocumentResource extends BaseResource {
|
|||||||
*
|
*
|
||||||
* @param limit Page limit
|
* @param limit Page limit
|
||||||
* @param offset Page offset
|
* @param offset Page offset
|
||||||
|
* @param sortColumn Sort column
|
||||||
|
* @param asc Sorting
|
||||||
|
* @param search Search query
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
@ -278,7 +270,7 @@ public class DocumentResource extends BaseResource {
|
|||||||
|
|
||||||
for (DocumentDto documentDto : paginatedList.getResultList()) {
|
for (DocumentDto documentDto : paginatedList.getResultList()) {
|
||||||
// Get tags added by the current user on this document
|
// Get tags added by the current user on this document
|
||||||
List<TagDto> tagDtoList = tagDao.getByDocumentId(documentDto.getId(), principal.getId());
|
List<TagDto> tagDtoList = tagDao.findByCriteria(new TagCriteria().setTargetIdList(getTargetIdList(null)).setDocumentId(documentDto.getId()), new SortCriteria(1, true));
|
||||||
JsonArrayBuilder tags = Json.createArrayBuilder();
|
JsonArrayBuilder tags = Json.createArrayBuilder();
|
||||||
for (TagDto tagDto : tagDtoList) {
|
for (TagDto tagDto : tagDtoList) {
|
||||||
tags.add(Json.createObjectBuilder()
|
tags.add(Json.createObjectBuilder()
|
||||||
@ -338,20 +330,23 @@ public class DocumentResource extends BaseResource {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params[0].equals("tag")) {
|
switch (params[0]) {
|
||||||
|
case "tag":
|
||||||
// New tag criteria
|
// New tag criteria
|
||||||
List<Tag> tagList = tagDao.findByName(principal.getId(), params[1]);
|
List<TagDto> tagDtoList = tagDao.findByCriteria(new TagCriteria().setTargetIdList(getTargetIdList(null)).setNameLike(params[1]), null);
|
||||||
if (documentCriteria.getTagIdList() == null) {
|
if (documentCriteria.getTagIdList() == null) {
|
||||||
documentCriteria.setTagIdList(new ArrayList<String>());
|
documentCriteria.setTagIdList(new ArrayList<String>());
|
||||||
}
|
}
|
||||||
if (tagList.size() == 0) {
|
if (tagDtoList.size() == 0) {
|
||||||
// No tag found, the request must returns nothing
|
// No tag found, the request must returns nothing
|
||||||
documentCriteria.getTagIdList().add(UUID.randomUUID().toString());
|
documentCriteria.getTagIdList().add(UUID.randomUUID().toString());
|
||||||
}
|
}
|
||||||
for (Tag tag : tagList) {
|
for (TagDto tagDto : tagDtoList) {
|
||||||
documentCriteria.getTagIdList().add(tag.getId());
|
documentCriteria.getTagIdList().add(tagDto.getId());
|
||||||
}
|
}
|
||||||
} else if (params[0].equals("after") || params[0].equals("before")) {
|
break;
|
||||||
|
case "after":
|
||||||
|
case "before":
|
||||||
// New date span criteria
|
// New date span criteria
|
||||||
try {
|
try {
|
||||||
DateTime date = formatter.parseDateTime(params[1]);
|
DateTime date = formatter.parseDateTime(params[1]);
|
||||||
@ -362,7 +357,8 @@ public class DocumentResource extends BaseResource {
|
|||||||
if (params[0].equals("before")) documentCriteria.setCreateDateMax(new Date(0));
|
if (params[0].equals("before")) documentCriteria.setCreateDateMax(new Date(0));
|
||||||
else documentCriteria.setCreateDateMin(new Date(Long.MAX_VALUE / 2));
|
else documentCriteria.setCreateDateMin(new Date(Long.MAX_VALUE / 2));
|
||||||
}
|
}
|
||||||
} else if (params[0].equals("at")) {
|
break;
|
||||||
|
case "at":
|
||||||
// New specific date criteria
|
// New specific date criteria
|
||||||
try {
|
try {
|
||||||
if (params[1].length() == 10) {
|
if (params[1].length() == 10) {
|
||||||
@ -383,17 +379,20 @@ public class DocumentResource extends BaseResource {
|
|||||||
documentCriteria.setCreateDateMin(new Date(0));
|
documentCriteria.setCreateDateMin(new Date(0));
|
||||||
documentCriteria.setCreateDateMax(new Date(0));
|
documentCriteria.setCreateDateMax(new Date(0));
|
||||||
}
|
}
|
||||||
} else if (params[0].equals("shared")) {
|
break;
|
||||||
|
case "shared":
|
||||||
// New shared state criteria
|
// New shared state criteria
|
||||||
if (params[1].equals("yes")) {
|
if (params[1].equals("yes")) {
|
||||||
documentCriteria.setShared(true);
|
documentCriteria.setShared(true);
|
||||||
}
|
}
|
||||||
} else if (params[0].equals("lang")) {
|
break;
|
||||||
|
case "lang":
|
||||||
// New language criteria
|
// New language criteria
|
||||||
if (Constants.SUPPORTED_LANGUAGES.contains(params[1])) {
|
if (Constants.SUPPORTED_LANGUAGES.contains(params[1])) {
|
||||||
documentCriteria.setLanguage(params[1]);
|
documentCriteria.setLanguage(params[1]);
|
||||||
}
|
}
|
||||||
} else if (params[0].equals("by")) {
|
break;
|
||||||
|
case "by":
|
||||||
// New creator criteria
|
// New creator criteria
|
||||||
User user = userDao.getActiveByUsername(params[1]);
|
User user = userDao.getActiveByUsername(params[1]);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
@ -403,11 +402,14 @@ public class DocumentResource extends BaseResource {
|
|||||||
// This user exists, search its documents
|
// This user exists, search its documents
|
||||||
documentCriteria.setCreatorId(user.getId());
|
documentCriteria.setCreatorId(user.getId());
|
||||||
}
|
}
|
||||||
} else if (params[0].equals("full")) {
|
break;
|
||||||
|
case "full":
|
||||||
// New full content search criteria
|
// New full content search criteria
|
||||||
fullQuery.add(params[1]);
|
fullQuery.add(params[1]);
|
||||||
} else {
|
break;
|
||||||
|
default:
|
||||||
query.add(criteria);
|
query.add(criteria);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,7 +423,16 @@ public class DocumentResource extends BaseResource {
|
|||||||
*
|
*
|
||||||
* @param title Title
|
* @param title Title
|
||||||
* @param description Description
|
* @param description Description
|
||||||
* @param tags Tags
|
* @param subject Subject
|
||||||
|
* @param identifier Identifier
|
||||||
|
* @param publisher Publisher
|
||||||
|
* @param format Format
|
||||||
|
* @param source Source
|
||||||
|
* @param type Type
|
||||||
|
* @param coverage Coverage
|
||||||
|
* @param rights Rights
|
||||||
|
* @param tagList Tags
|
||||||
|
* @param relationList Relations
|
||||||
* @param language Language
|
* @param language Language
|
||||||
* @param createDateStr Creation date
|
* @param createDateStr Creation date
|
||||||
* @return Response
|
* @return Response
|
||||||
@ -573,7 +584,7 @@ public class DocumentResource extends BaseResource {
|
|||||||
DocumentDao documentDao = new DocumentDao();
|
DocumentDao documentDao = new DocumentDao();
|
||||||
Document document = documentDao.getById(id);
|
Document document = documentDao.getById(id);
|
||||||
if (document == null) {
|
if (document == null) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the document
|
// Update the document
|
||||||
@ -594,7 +605,7 @@ public class DocumentResource extends BaseResource {
|
|||||||
document.setCreateDate(createDate);
|
document.setCreateDate(createDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
document = documentDao.update(document, principal.getId());
|
documentDao.update(document, principal.getId());
|
||||||
|
|
||||||
// Update tags
|
// Update tags
|
||||||
updateTagList(id, tagList);
|
updateTagList(id, tagList);
|
||||||
@ -624,9 +635,9 @@ public class DocumentResource extends BaseResource {
|
|||||||
TagDao tagDao = new TagDao();
|
TagDao tagDao = new TagDao();
|
||||||
Set<String> tagSet = new HashSet<>();
|
Set<String> tagSet = new HashSet<>();
|
||||||
Set<String> tagIdSet = new HashSet<>();
|
Set<String> tagIdSet = new HashSet<>();
|
||||||
List<Tag> tagDbList = tagDao.getByUserId(principal.getId());
|
List<TagDto> tagDtoList = tagDao.findByCriteria(new TagCriteria().setTargetIdList(getTargetIdList(null)), null);
|
||||||
for (Tag tagDb : tagDbList) {
|
for (TagDto tagDto : tagDtoList) {
|
||||||
tagIdSet.add(tagDb.getId());
|
tagIdSet.add(tagDto.getId());
|
||||||
}
|
}
|
||||||
for (String tagId : tagList) {
|
for (String tagId : tagList) {
|
||||||
if (!tagIdSet.contains(tagId)) {
|
if (!tagIdSet.contains(tagId)) {
|
||||||
@ -677,14 +688,14 @@ public class DocumentResource extends BaseResource {
|
|||||||
// Get the document
|
// Get the document
|
||||||
DocumentDao documentDao = new DocumentDao();
|
DocumentDao documentDao = new DocumentDao();
|
||||||
FileDao fileDao = new FileDao();
|
FileDao fileDao = new FileDao();
|
||||||
DocumentDto documentDto = documentDao.getDocument(id, PermType.WRITE, getTargetIdList(null));
|
AclDao aclDao = new AclDao();
|
||||||
if (documentDto == null) {
|
if (!aclDao.checkPermission(id, PermType.WRITE, getTargetIdList(null))) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
List<File> fileList = fileDao.getByDocumentId(principal.getId(), id);
|
List<File> fileList = fileDao.getByDocumentId(principal.getId(), id);
|
||||||
|
|
||||||
// Delete the document
|
// Delete the document
|
||||||
documentDao.delete(documentDto.getId(), principal.getId());
|
documentDao.delete(id, principal.getId());
|
||||||
|
|
||||||
// Raise file deleted events (don't bother sending document updated event)
|
// Raise file deleted events (don't bother sending document updated event)
|
||||||
for (File file : fileList) {
|
for (File file : fileList) {
|
||||||
@ -697,7 +708,7 @@ public class DocumentResource extends BaseResource {
|
|||||||
// Raise a document deleted event
|
// Raise a document deleted event
|
||||||
DocumentDeletedAsyncEvent documentDeletedAsyncEvent = new DocumentDeletedAsyncEvent();
|
DocumentDeletedAsyncEvent documentDeletedAsyncEvent = new DocumentDeletedAsyncEvent();
|
||||||
documentDeletedAsyncEvent.setUserId(principal.getId());
|
documentDeletedAsyncEvent.setUserId(principal.getId());
|
||||||
documentDeletedAsyncEvent.setDocumentId(documentDto.getId());
|
documentDeletedAsyncEvent.setDocumentId(id);
|
||||||
AppContext.getInstance().getAsyncEventBus().post(documentDeletedAsyncEvent);
|
AppContext.getInstance().getAsyncEventBus().post(documentDeletedAsyncEvent);
|
||||||
|
|
||||||
// Always return OK
|
// Always return OK
|
||||||
|
@ -16,17 +16,7 @@ import java.util.zip.ZipOutputStream;
|
|||||||
import javax.json.Json;
|
import javax.json.Json;
|
||||||
import javax.json.JsonArrayBuilder;
|
import javax.json.JsonArrayBuilder;
|
||||||
import javax.json.JsonObjectBuilder;
|
import javax.json.JsonObjectBuilder;
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.*;
|
||||||
import javax.ws.rs.DELETE;
|
|
||||||
import javax.ws.rs.FormParam;
|
|
||||||
import javax.ws.rs.GET;
|
|
||||||
import javax.ws.rs.POST;
|
|
||||||
import javax.ws.rs.PUT;
|
|
||||||
import javax.ws.rs.Path;
|
|
||||||
import javax.ws.rs.PathParam;
|
|
||||||
import javax.ws.rs.Produces;
|
|
||||||
import javax.ws.rs.QueryParam;
|
|
||||||
import javax.ws.rs.WebApplicationException;
|
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.Response.Status;
|
import javax.ws.rs.core.Response.Status;
|
||||||
@ -100,7 +90,7 @@ public class FileResource extends BaseResource {
|
|||||||
DocumentDao documentDao = new DocumentDao();
|
DocumentDao documentDao = new DocumentDao();
|
||||||
documentDto = documentDao.getDocument(documentId, PermType.WRITE, getTargetIdList(null));
|
documentDto = documentDao.getDocument(documentId, PermType.WRITE, getTargetIdList(null));
|
||||||
if (documentDto == null) {
|
if (documentDto == null) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +107,7 @@ public class FileResource extends BaseResource {
|
|||||||
String mimeType;
|
String mimeType;
|
||||||
try {
|
try {
|
||||||
mimeType = MimeTypeUtil.guessMimeType(fileInputStream);
|
mimeType = MimeTypeUtil.guessMimeType(fileInputStream);
|
||||||
} catch (Exception e) {
|
} catch (IOException e) {
|
||||||
throw new ServerException("ErrorGuessMime", "Error guessing mime type", e);
|
throw new ServerException("ErrorGuessMime", "Error guessing mime type", e);
|
||||||
}
|
}
|
||||||
if (mimeType == null) {
|
if (mimeType == null) {
|
||||||
@ -215,7 +205,7 @@ public class FileResource extends BaseResource {
|
|||||||
File file = fileDao.getFile(id, principal.getId());
|
File file = fileDao.getFile(id, principal.getId());
|
||||||
DocumentDto documentDto = documentDao.getDocument(documentId, PermType.WRITE, getTargetIdList(null));
|
DocumentDto documentDto = documentDao.getDocument(documentId, PermType.WRITE, getTargetIdList(null));
|
||||||
if (file == null || documentDto == null) {
|
if (file == null || documentDto == null) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the file is orphan
|
// Check that the file is orphan
|
||||||
@ -275,9 +265,9 @@ public class FileResource extends BaseResource {
|
|||||||
ValidationUtil.validateRequired(idList, "order");
|
ValidationUtil.validateRequired(idList, "order");
|
||||||
|
|
||||||
// Get the document
|
// Get the document
|
||||||
DocumentDao documentDao = new DocumentDao();
|
AclDao aclDao = new AclDao();
|
||||||
if (documentDao.getDocument(documentId, PermType.WRITE, getTargetIdList(null)) == null) {
|
if (!aclDao.checkPermission(documentId, PermType.WRITE, getTargetIdList(null))) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reorder files
|
// Reorder files
|
||||||
@ -313,7 +303,7 @@ public class FileResource extends BaseResource {
|
|||||||
if (documentId != null) {
|
if (documentId != null) {
|
||||||
AclDao aclDao = new AclDao();
|
AclDao aclDao = new AclDao();
|
||||||
if (!aclDao.checkPermission(documentId, PermType.READ, getTargetIdList(shareId))) {
|
if (!aclDao.checkPermission(documentId, PermType.READ, getTargetIdList(shareId))) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
} else if (!authenticated) {
|
} else if (!authenticated) {
|
||||||
throw new ForbiddenClientException();
|
throw new ForbiddenClientException();
|
||||||
@ -357,21 +347,20 @@ public class FileResource extends BaseResource {
|
|||||||
|
|
||||||
// Get the file
|
// Get the file
|
||||||
FileDao fileDao = new FileDao();
|
FileDao fileDao = new FileDao();
|
||||||
DocumentDao documentDao = new DocumentDao();
|
AclDao aclDao = new AclDao();
|
||||||
File file = fileDao.getFile(id);
|
File file = fileDao.getFile(id);
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
DocumentDto documentDto = null;
|
|
||||||
if (file.getDocumentId() == null) {
|
if (file.getDocumentId() == null) {
|
||||||
// It's an orphan file
|
// It's an orphan file
|
||||||
if (!file.getUserId().equals(principal.getId())) {
|
if (!file.getUserId().equals(principal.getId())) {
|
||||||
// But not ours
|
// But not ours
|
||||||
throw new ForbiddenClientException();
|
throw new ForbiddenClientException();
|
||||||
}
|
}
|
||||||
} else if ((documentDto = documentDao.getDocument(file.getDocumentId(), PermType.WRITE, getTargetIdList(null))) == null) {
|
} else if (!aclDao.checkPermission(file.getDocumentId(), PermType.WRITE, getTargetIdList(null))) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the file
|
// Delete the file
|
||||||
@ -394,11 +383,11 @@ public class FileResource extends BaseResource {
|
|||||||
fileDeletedAsyncEvent.setFile(file);
|
fileDeletedAsyncEvent.setFile(file);
|
||||||
AppContext.getInstance().getAsyncEventBus().post(fileDeletedAsyncEvent);
|
AppContext.getInstance().getAsyncEventBus().post(fileDeletedAsyncEvent);
|
||||||
|
|
||||||
if (documentDto != null) {
|
if (file.getDocumentId() != null) {
|
||||||
// Raise a new document updated
|
// Raise a new document updated
|
||||||
DocumentUpdatedAsyncEvent documentUpdatedAsyncEvent = new DocumentUpdatedAsyncEvent();
|
DocumentUpdatedAsyncEvent documentUpdatedAsyncEvent = new DocumentUpdatedAsyncEvent();
|
||||||
documentUpdatedAsyncEvent.setUserId(principal.getId());
|
documentUpdatedAsyncEvent.setUserId(principal.getId());
|
||||||
documentUpdatedAsyncEvent.setDocumentId(documentDto.getId());
|
documentUpdatedAsyncEvent.setDocumentId(file.getDocumentId());
|
||||||
AppContext.getInstance().getAsyncEventBus().post(documentUpdatedAsyncEvent);
|
AppContext.getInstance().getAsyncEventBus().post(documentUpdatedAsyncEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,7 +422,7 @@ public class FileResource extends BaseResource {
|
|||||||
UserDao userDao = new UserDao();
|
UserDao userDao = new UserDao();
|
||||||
File file = fileDao.getFile(fileId);
|
File file = fileDao.getFile(fileId);
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file.getDocumentId() == null) {
|
if (file.getDocumentId() == null) {
|
||||||
@ -454,7 +443,7 @@ public class FileResource extends BaseResource {
|
|||||||
// Get the stored file
|
// Get the stored file
|
||||||
java.nio.file.Path storedFile;
|
java.nio.file.Path storedFile;
|
||||||
String mimeType;
|
String mimeType;
|
||||||
boolean decrypt = false;
|
boolean decrypt;
|
||||||
if (size != null) {
|
if (size != null) {
|
||||||
storedFile = DirectoryUtil.getStorageDirectory().resolve(fileId + "_" + size);
|
storedFile = DirectoryUtil.getStorageDirectory().resolve(fileId + "_" + size);
|
||||||
mimeType = MimeType.IMAGE_JPEG; // Thumbnails are JPEG
|
mimeType = MimeType.IMAGE_JPEG; // Thumbnails are JPEG
|
||||||
@ -488,8 +477,12 @@ public class FileResource extends BaseResource {
|
|||||||
try {
|
try {
|
||||||
ByteStreams.copy(responseInputStream, outputStream);
|
ByteStreams.copy(responseInputStream, outputStream);
|
||||||
} finally {
|
} finally {
|
||||||
|
try {
|
||||||
responseInputStream.close();
|
responseInputStream.close();
|
||||||
outputStream.close();
|
outputStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -521,7 +514,7 @@ public class FileResource extends BaseResource {
|
|||||||
DocumentDao documentDao = new DocumentDao();
|
DocumentDao documentDao = new DocumentDao();
|
||||||
DocumentDto documentDto = documentDao.getDocument(documentId, PermType.READ, getTargetIdList(shareId));
|
DocumentDto documentDto = documentDao.getDocument(documentId, PermType.READ, getTargetIdList(shareId));
|
||||||
if (documentDto == null) {
|
if (documentDto == null) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get files and user associated with this document
|
// Get files and user associated with this document
|
||||||
|
@ -1,22 +1,5 @@
|
|||||||
package com.sismics.docs.rest.resource;
|
package com.sismics.docs.rest.resource;
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.json.Json;
|
|
||||||
import javax.json.JsonArrayBuilder;
|
|
||||||
import javax.json.JsonObjectBuilder;
|
|
||||||
import javax.ws.rs.DELETE;
|
|
||||||
import javax.ws.rs.FormParam;
|
|
||||||
import javax.ws.rs.GET;
|
|
||||||
import javax.ws.rs.POST;
|
|
||||||
import javax.ws.rs.PUT;
|
|
||||||
import javax.ws.rs.Path;
|
|
||||||
import javax.ws.rs.PathParam;
|
|
||||||
import javax.ws.rs.QueryParam;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import javax.ws.rs.core.Response.Status;
|
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.sismics.docs.core.dao.jpa.GroupDao;
|
import com.sismics.docs.core.dao.jpa.GroupDao;
|
||||||
import com.sismics.docs.core.dao.jpa.UserDao;
|
import com.sismics.docs.core.dao.jpa.UserDao;
|
||||||
@ -34,6 +17,14 @@ import com.sismics.rest.exception.ForbiddenClientException;
|
|||||||
import com.sismics.rest.util.JsonUtil;
|
import com.sismics.rest.util.JsonUtil;
|
||||||
import com.sismics.rest.util.ValidationUtil;
|
import com.sismics.rest.util.ValidationUtil;
|
||||||
|
|
||||||
|
import javax.json.Json;
|
||||||
|
import javax.json.JsonArrayBuilder;
|
||||||
|
import javax.json.JsonObjectBuilder;
|
||||||
|
import javax.ws.rs.*;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Group REST resources.
|
* Group REST resources.
|
||||||
*
|
*
|
||||||
@ -109,12 +100,12 @@ public class GroupResource extends BaseResource {
|
|||||||
GroupDao groupDao = new GroupDao();
|
GroupDao groupDao = new GroupDao();
|
||||||
Group group = groupDao.getActiveByName(groupName);
|
Group group = groupDao.getActiveByName(groupName);
|
||||||
if (group == null) {
|
if (group == null) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avoid duplicates
|
// Avoid duplicates
|
||||||
Group existingGroup = groupDao.getActiveByName(name);
|
Group existingGroup = groupDao.getActiveByName(name);
|
||||||
if (existingGroup != null && existingGroup.getId() != group.getId()) {
|
if (existingGroup != null && !existingGroup.getId().equals(group.getId())) {
|
||||||
throw new ClientException("GroupAlreadyExists", MessageFormat.format("This group already exists: {0}", name));
|
throw new ClientException("GroupAlreadyExists", MessageFormat.format("This group already exists: {0}", name));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +146,7 @@ public class GroupResource extends BaseResource {
|
|||||||
GroupDao groupDao = new GroupDao();
|
GroupDao groupDao = new GroupDao();
|
||||||
Group group = groupDao.getActiveByName(groupName);
|
Group group = groupDao.getActiveByName(groupName);
|
||||||
if (group == null) {
|
if (group == null) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the group
|
// Delete the group
|
||||||
@ -191,14 +182,14 @@ public class GroupResource extends BaseResource {
|
|||||||
GroupDao groupDao = new GroupDao();
|
GroupDao groupDao = new GroupDao();
|
||||||
Group group = groupDao.getActiveByName(groupName);
|
Group group = groupDao.getActiveByName(groupName);
|
||||||
if (group == null) {
|
if (group == null) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the user
|
// Get the user
|
||||||
UserDao userDao = new UserDao();
|
UserDao userDao = new UserDao();
|
||||||
User user = userDao.getActiveByUsername(username);
|
User user = userDao.getActiveByUsername(username);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avoid duplicates
|
// Avoid duplicates
|
||||||
@ -248,14 +239,14 @@ public class GroupResource extends BaseResource {
|
|||||||
GroupDao groupDao = new GroupDao();
|
GroupDao groupDao = new GroupDao();
|
||||||
Group group = groupDao.getActiveByName(groupName);
|
Group group = groupDao.getActiveByName(groupName);
|
||||||
if (group == null) {
|
if (group == null) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the user
|
// Get the user
|
||||||
UserDao userDao = new UserDao();
|
UserDao userDao = new UserDao();
|
||||||
User user = userDao.getActiveByUsername(username);
|
User user = userDao.getActiveByUsername(username);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the membership
|
// Remove the membership
|
||||||
@ -315,7 +306,7 @@ public class GroupResource extends BaseResource {
|
|||||||
GroupDao groupDao = new GroupDao();
|
GroupDao groupDao = new GroupDao();
|
||||||
Group group = groupDao.getActiveByName(groupName);
|
Group group = groupDao.getActiveByName(groupName);
|
||||||
if (group == null) {
|
if (group == null) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the response
|
// Build the response
|
||||||
|
@ -1,23 +1,9 @@
|
|||||||
package com.sismics.docs.rest.resource;
|
package com.sismics.docs.rest.resource;
|
||||||
|
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.json.Json;
|
|
||||||
import javax.json.JsonObjectBuilder;
|
|
||||||
import javax.ws.rs.DELETE;
|
|
||||||
import javax.ws.rs.FormParam;
|
|
||||||
import javax.ws.rs.PUT;
|
|
||||||
import javax.ws.rs.Path;
|
|
||||||
import javax.ws.rs.PathParam;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import javax.ws.rs.core.Response.Status;
|
|
||||||
|
|
||||||
import com.sismics.docs.core.constant.AclTargetType;
|
import com.sismics.docs.core.constant.AclTargetType;
|
||||||
import com.sismics.docs.core.constant.PermType;
|
import com.sismics.docs.core.constant.PermType;
|
||||||
import com.sismics.docs.core.dao.jpa.AclDao;
|
import com.sismics.docs.core.dao.jpa.AclDao;
|
||||||
import com.sismics.docs.core.dao.jpa.DocumentDao;
|
|
||||||
import com.sismics.docs.core.dao.jpa.ShareDao;
|
import com.sismics.docs.core.dao.jpa.ShareDao;
|
||||||
import com.sismics.docs.core.model.jpa.Acl;
|
import com.sismics.docs.core.model.jpa.Acl;
|
||||||
import com.sismics.docs.core.model.jpa.Share;
|
import com.sismics.docs.core.model.jpa.Share;
|
||||||
@ -26,6 +12,13 @@ import com.sismics.rest.exception.ForbiddenClientException;
|
|||||||
import com.sismics.rest.util.JsonUtil;
|
import com.sismics.rest.util.JsonUtil;
|
||||||
import com.sismics.rest.util.ValidationUtil;
|
import com.sismics.rest.util.ValidationUtil;
|
||||||
|
|
||||||
|
import javax.json.Json;
|
||||||
|
import javax.json.JsonObjectBuilder;
|
||||||
|
import javax.ws.rs.*;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Share REST resources.
|
* Share REST resources.
|
||||||
*
|
*
|
||||||
@ -52,10 +45,10 @@ public class ShareResource extends BaseResource {
|
|||||||
ValidationUtil.validateRequired(documentId, "id");
|
ValidationUtil.validateRequired(documentId, "id");
|
||||||
name = ValidationUtil.validateLength(name, "name", 1, 36, true);
|
name = ValidationUtil.validateLength(name, "name", 1, 36, true);
|
||||||
|
|
||||||
// Get the document
|
// Check write permission on the document
|
||||||
DocumentDao documentDao = new DocumentDao();
|
AclDao aclDao = new AclDao();
|
||||||
if (documentDao.getDocument(documentId, PermType.WRITE, getTargetIdList(null)) == null) {
|
if (!aclDao.checkPermission(documentId, PermType.WRITE, getTargetIdList(null))) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the share
|
// Create the share
|
||||||
@ -65,7 +58,6 @@ public class ShareResource extends BaseResource {
|
|||||||
shareDao.create(share);
|
shareDao.create(share);
|
||||||
|
|
||||||
// Create the ACL
|
// Create the ACL
|
||||||
AclDao aclDao = new AclDao();
|
|
||||||
Acl acl = new Acl();
|
Acl acl = new Acl();
|
||||||
acl.setSourceId(documentId);
|
acl.setSourceId(documentId);
|
||||||
acl.setPerm(PermType.READ);
|
acl.setPerm(PermType.READ);
|
||||||
|
@ -1,29 +1,28 @@
|
|||||||
package com.sismics.docs.rest.resource;
|
package com.sismics.docs.rest.resource;
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
import com.google.common.collect.Sets;
|
||||||
import java.util.List;
|
import com.sismics.docs.core.constant.PermType;
|
||||||
|
import com.sismics.docs.core.dao.jpa.AclDao;
|
||||||
|
import com.sismics.docs.core.dao.jpa.TagDao;
|
||||||
|
import com.sismics.docs.core.dao.jpa.criteria.TagCriteria;
|
||||||
|
import com.sismics.docs.core.dao.jpa.dto.TagDto;
|
||||||
|
import com.sismics.docs.core.model.jpa.Acl;
|
||||||
|
import com.sismics.docs.core.model.jpa.Tag;
|
||||||
|
import com.sismics.docs.core.util.jpa.SortCriteria;
|
||||||
|
import com.sismics.rest.exception.ClientException;
|
||||||
|
import com.sismics.rest.exception.ForbiddenClientException;
|
||||||
|
import com.sismics.rest.util.AclUtil;
|
||||||
|
import com.sismics.rest.util.ValidationUtil;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
|
||||||
import javax.json.Json;
|
import javax.json.Json;
|
||||||
import javax.json.JsonArrayBuilder;
|
import javax.json.JsonArrayBuilder;
|
||||||
import javax.json.JsonObjectBuilder;
|
import javax.json.JsonObjectBuilder;
|
||||||
import javax.ws.rs.DELETE;
|
import javax.ws.rs.*;
|
||||||
import javax.ws.rs.FormParam;
|
|
||||||
import javax.ws.rs.GET;
|
|
||||||
import javax.ws.rs.POST;
|
|
||||||
import javax.ws.rs.PUT;
|
|
||||||
import javax.ws.rs.Path;
|
|
||||||
import javax.ws.rs.PathParam;
|
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
import java.text.MessageFormat;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import com.sismics.docs.core.dao.jpa.TagDao;
|
|
||||||
import com.sismics.docs.core.dao.jpa.dto.TagStatDto;
|
|
||||||
import com.sismics.docs.core.model.jpa.Tag;
|
|
||||||
import com.sismics.rest.exception.ClientException;
|
|
||||||
import com.sismics.rest.exception.ForbiddenClientException;
|
|
||||||
import com.sismics.rest.util.JsonUtil;
|
|
||||||
import com.sismics.rest.util.ValidationUtil;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tag REST resources.
|
* Tag REST resources.
|
||||||
@ -33,7 +32,7 @@ import com.sismics.rest.util.ValidationUtil;
|
|||||||
@Path("/tag")
|
@Path("/tag")
|
||||||
public class TagResource extends BaseResource {
|
public class TagResource extends BaseResource {
|
||||||
/**
|
/**
|
||||||
* Returns the list of all tags.
|
* Returns the list of all visible tags.
|
||||||
*
|
*
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
@ -45,14 +44,25 @@ public class TagResource extends BaseResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TagDao tagDao = new TagDao();
|
TagDao tagDao = new TagDao();
|
||||||
List<Tag> tagList = tagDao.getByUserId(principal.getId());
|
List<TagDto> tagDtoList = tagDao.findByCriteria(new TagCriteria().setTargetIdList(getTargetIdList(null)), new SortCriteria(1, true));
|
||||||
|
|
||||||
|
// Extract tag IDs
|
||||||
|
Set<String> tagIdSet = Sets.newHashSet();
|
||||||
|
for (TagDto tagDto : tagDtoList) {
|
||||||
|
tagIdSet.add(tagDto.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the response
|
||||||
JsonArrayBuilder items = Json.createArrayBuilder();
|
JsonArrayBuilder items = Json.createArrayBuilder();
|
||||||
for (Tag tag : tagList) {
|
for (TagDto tagDto : tagDtoList) {
|
||||||
items.add(Json.createObjectBuilder()
|
JsonObjectBuilder item = Json.createObjectBuilder()
|
||||||
.add("id", tag.getId())
|
.add("id", tagDto.getId())
|
||||||
.add("name", tag.getName())
|
.add("name", tagDto.getName())
|
||||||
.add("color", tag.getColor())
|
.add("color", tagDto.getColor());
|
||||||
.add("parent", JsonUtil.nullable(tag.getParentId())));
|
if (tagIdSet.contains(tagDto.getParentId())) {
|
||||||
|
item.add("parent", tagDto.getParentId());
|
||||||
|
}
|
||||||
|
items.add(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonObjectBuilder response = Json.createObjectBuilder()
|
JsonObjectBuilder response = Json.createObjectBuilder()
|
||||||
@ -61,39 +71,52 @@ public class TagResource extends BaseResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns stats on tags.
|
* Returns a tag.
|
||||||
*
|
*
|
||||||
|
* @param id Tag ID
|
||||||
* @return Response
|
* @return Response
|
||||||
* @throws JSONException
|
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
@Path("/stats")
|
@Path("{id: [a-z0-9\\-]+}")
|
||||||
public Response stats() {
|
public Response get(@PathParam("id") String id) {
|
||||||
if (!authenticate()) {
|
if (!authenticate()) {
|
||||||
throw new ForbiddenClientException();
|
throw new ForbiddenClientException();
|
||||||
}
|
}
|
||||||
|
|
||||||
TagDao tagDao = new TagDao();
|
TagDao tagDao = new TagDao();
|
||||||
List<TagStatDto> tagStatDtoList = tagDao.getStats(principal.getId());
|
List<TagDto> tagDtoList = tagDao.findByCriteria(new TagCriteria().setTargetIdList(getTargetIdList(null)).setId(id), null);
|
||||||
JsonArrayBuilder items = Json.createArrayBuilder();
|
if (tagDtoList.size() == 0) {
|
||||||
for (TagStatDto tagStatDto : tagStatDtoList) {
|
throw new NotFoundException();
|
||||||
items.add(Json.createObjectBuilder()
|
|
||||||
.add("id", tagStatDto.getId())
|
|
||||||
.add("name", tagStatDto.getName())
|
|
||||||
.add("color", tagStatDto.getColor())
|
|
||||||
.add("parent", JsonUtil.nullable(tagStatDto.getParentId()))
|
|
||||||
.add("count", tagStatDto.getCount()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonObjectBuilder response = Json.createObjectBuilder()
|
// Add tag informatiosn
|
||||||
.add("stats", items);
|
TagDto tagDto = tagDtoList.get(0);
|
||||||
return Response.ok().entity(response.build()).build();
|
JsonObjectBuilder tag = Json.createObjectBuilder()
|
||||||
|
.add("id", tagDto.getId())
|
||||||
|
.add("creator", tagDto.getCreator())
|
||||||
|
.add("name", tagDto.getName())
|
||||||
|
.add("color", tagDto.getColor());
|
||||||
|
|
||||||
|
// Add the parent if its visible
|
||||||
|
if (tagDto.getParentId() != null) {
|
||||||
|
AclDao aclDao = new AclDao();
|
||||||
|
if (aclDao.checkPermission(tagDto.getParentId(), PermType.READ, getTargetIdList(null))) {
|
||||||
|
tag.add("parent", tagDto.getParentId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add ACL
|
||||||
|
AclUtil.addAcls(tag, id, getTargetIdList(null));
|
||||||
|
|
||||||
|
return Response.ok().entity(tag.build()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new tag.
|
* Creates a new tag.
|
||||||
*
|
*
|
||||||
* @param name Name
|
* @param name Name
|
||||||
|
* @param color Color
|
||||||
|
* @param parentId Parent ID
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
@PUT
|
@PUT
|
||||||
@ -114,31 +137,40 @@ public class TagResource extends BaseResource {
|
|||||||
throw new ClientException("SpacesNotAllowed", "Spaces are not allowed in tag name");
|
throw new ClientException("SpacesNotAllowed", "Spaces are not allowed in tag name");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the tag
|
|
||||||
TagDao tagDao = new TagDao();
|
|
||||||
Tag tag = tagDao.getByName(principal.getId(), name);
|
|
||||||
if (tag != null) {
|
|
||||||
throw new ClientException("AlreadyExistingTag", MessageFormat.format("Tag already exists: {0}", name));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the parent
|
// Check the parent
|
||||||
if (StringUtils.isEmpty(parentId)) {
|
if (StringUtils.isEmpty(parentId)) {
|
||||||
parentId = null;
|
parentId = null;
|
||||||
} else {
|
} else {
|
||||||
Tag parentTag = tagDao.getByTagId(principal.getId(), parentId);
|
AclDao aclDao = new AclDao();
|
||||||
if (parentTag == null) {
|
if (!aclDao.checkPermission(parentId, PermType.READ, getTargetIdList(null))) {
|
||||||
throw new ClientException("ParentNotFound", MessageFormat.format("Parent not found: {0}", parentId));
|
throw new ClientException("ParentNotFound", MessageFormat.format("Parent not found: {0}", parentId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the tag
|
// Create the tag
|
||||||
tag = new Tag();
|
TagDao tagDao = new TagDao();
|
||||||
|
Tag tag = new Tag();
|
||||||
tag.setName(name);
|
tag.setName(name);
|
||||||
tag.setColor(color);
|
tag.setColor(color);
|
||||||
tag.setUserId(principal.getId());
|
tag.setUserId(principal.getId());
|
||||||
tag.setParentId(parentId);
|
tag.setParentId(parentId);
|
||||||
String id = tagDao.create(tag, principal.getId());
|
String id = tagDao.create(tag, principal.getId());
|
||||||
|
|
||||||
|
// Create read ACL
|
||||||
|
AclDao aclDao = new AclDao();
|
||||||
|
Acl acl = new Acl();
|
||||||
|
acl.setPerm(PermType.READ);
|
||||||
|
acl.setSourceId(id);
|
||||||
|
acl.setTargetId(principal.getId());
|
||||||
|
aclDao.create(acl, principal.getId());
|
||||||
|
|
||||||
|
// Create write ACL
|
||||||
|
acl = new Acl();
|
||||||
|
acl.setPerm(PermType.WRITE);
|
||||||
|
acl.setSourceId(id);
|
||||||
|
acl.setTargetId(principal.getId());
|
||||||
|
aclDao.create(acl, principal.getId());
|
||||||
|
|
||||||
JsonObjectBuilder response = Json.createObjectBuilder()
|
JsonObjectBuilder response = Json.createObjectBuilder()
|
||||||
.add("id", id);
|
.add("id", id);
|
||||||
return Response.ok().entity(response.build()).build();
|
return Response.ok().entity(response.build()).build();
|
||||||
@ -148,6 +180,8 @@ public class TagResource extends BaseResource {
|
|||||||
* Update a tag.
|
* Update a tag.
|
||||||
*
|
*
|
||||||
* @param name Name
|
* @param name Name
|
||||||
|
* @param color Color
|
||||||
|
* @param parentId Parent ID
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
@POST
|
@POST
|
||||||
@ -170,30 +204,24 @@ public class TagResource extends BaseResource {
|
|||||||
throw new ClientException("SpacesNotAllowed", "Spaces are not allowed in tag name");
|
throw new ClientException("SpacesNotAllowed", "Spaces are not allowed in tag name");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the tag
|
// Check permission
|
||||||
TagDao tagDao = new TagDao();
|
AclDao aclDao = new AclDao();
|
||||||
Tag tag = tagDao.getByTagId(principal.getId(), id);
|
if (!aclDao.checkPermission(id, PermType.WRITE, getTargetIdList(null))) {
|
||||||
if (tag == null) {
|
throw new NotFoundException();
|
||||||
throw new ClientException("TagNotFound", MessageFormat.format("Tag not found: {0}", id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the parent
|
// Check the parent
|
||||||
if (StringUtils.isEmpty(parentId)) {
|
if (StringUtils.isEmpty(parentId)) {
|
||||||
parentId = null;
|
parentId = null;
|
||||||
} else {
|
} else {
|
||||||
Tag parentTag = tagDao.getByTagId(principal.getId(), parentId);
|
if (!aclDao.checkPermission(parentId, PermType.READ, getTargetIdList(null))) {
|
||||||
if (parentTag == null) {
|
|
||||||
throw new ClientException("ParentNotFound", MessageFormat.format("Parent not found: {0}", parentId));
|
throw new ClientException("ParentNotFound", MessageFormat.format("Parent not found: {0}", parentId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for name duplicate
|
|
||||||
Tag tagDuplicate = tagDao.getByName(principal.getId(), name);
|
|
||||||
if (tagDuplicate != null && !tagDuplicate.getId().equals(id)) {
|
|
||||||
throw new ClientException("AlreadyExistingTag", MessageFormat.format("Tag already exists: {0}", name));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the tag
|
// Update the tag
|
||||||
|
TagDao tagDao = new TagDao();
|
||||||
|
Tag tag = tagDao.getById(id);
|
||||||
if (!StringUtils.isEmpty(name)) {
|
if (!StringUtils.isEmpty(name)) {
|
||||||
tag.setName(name);
|
tag.setName(name);
|
||||||
}
|
}
|
||||||
@ -213,26 +241,26 @@ public class TagResource extends BaseResource {
|
|||||||
/**
|
/**
|
||||||
* Delete a tag.
|
* Delete a tag.
|
||||||
*
|
*
|
||||||
* @param tagId Tag ID
|
* @param id Tag ID
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
@DELETE
|
@DELETE
|
||||||
@Path("{id: [a-z0-9\\-]+}")
|
@Path("{id: [a-z0-9\\-]+}")
|
||||||
public Response delete(
|
public Response delete(
|
||||||
@PathParam("id") String tagId) {
|
@PathParam("id") String id) {
|
||||||
if (!authenticate()) {
|
if (!authenticate()) {
|
||||||
throw new ForbiddenClientException();
|
throw new ForbiddenClientException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the tag
|
// Get the tag
|
||||||
TagDao tagDao = new TagDao();
|
AclDao aclDao = new AclDao();
|
||||||
Tag tag = tagDao.getByTagId(principal.getId(), tagId);
|
if (!aclDao.checkPermission(id, PermType.WRITE, getTargetIdList(null))) {
|
||||||
if (tag == null) {
|
throw new NotFoundException();
|
||||||
throw new ClientException("TagNotFound", MessageFormat.format("Tag not found: {0}", tagId));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the tag
|
// Delete the tag
|
||||||
tagDao.delete(tagId, principal.getId());
|
TagDao tagDao = new TagDao();
|
||||||
|
tagDao.delete(id, principal.getId());
|
||||||
|
|
||||||
// Always return OK
|
// Always return OK
|
||||||
JsonObjectBuilder response = Json.createObjectBuilder()
|
JsonObjectBuilder response = Json.createObjectBuilder()
|
||||||
|
@ -0,0 +1,214 @@
|
|||||||
|
package com.sismics.docs.rest.resource;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
|
import com.google.common.io.ByteStreams;
|
||||||
|
import com.sismics.docs.core.constant.ConfigType;
|
||||||
|
import com.sismics.docs.core.dao.jpa.ConfigDao;
|
||||||
|
import com.sismics.docs.core.model.jpa.Config;
|
||||||
|
import com.sismics.docs.core.util.DirectoryUtil;
|
||||||
|
import com.sismics.docs.rest.constant.BaseFunction;
|
||||||
|
import com.sismics.rest.exception.ClientException;
|
||||||
|
import com.sismics.rest.exception.ForbiddenClientException;
|
||||||
|
import com.sismics.rest.exception.ServerException;
|
||||||
|
import com.sismics.rest.util.JsonUtil;
|
||||||
|
import com.sismics.rest.util.ValidationUtil;
|
||||||
|
import com.sismics.util.css.Selector;
|
||||||
|
import org.glassfish.jersey.media.multipart.FormDataBodyPart;
|
||||||
|
import org.glassfish.jersey.media.multipart.FormDataParam;
|
||||||
|
|
||||||
|
import javax.json.*;
|
||||||
|
import javax.ws.rs.*;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import javax.ws.rs.core.StreamingOutput;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Theme REST resources.
|
||||||
|
*
|
||||||
|
* @author bgamard
|
||||||
|
*/
|
||||||
|
@Path("/theme")
|
||||||
|
public class ThemeResource extends BaseResource {
|
||||||
|
// Filenames for images in theme directory
|
||||||
|
private static final String LOGO_IMAGE = "logo";
|
||||||
|
private static final String BACKGROUND_IMAGE = "background";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns custom CSS stylesheet.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Path("/stylesheet")
|
||||||
|
@Produces("text/css")
|
||||||
|
public Response stylesheet() {
|
||||||
|
JsonObject themeConfig = getThemeConfig();
|
||||||
|
|
||||||
|
// Build the stylesheet
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(new Selector(".navbar")
|
||||||
|
.rule("background-color", themeConfig.getString("color", "#263238")));
|
||||||
|
sb.append(themeConfig.getString("css", ""));
|
||||||
|
|
||||||
|
return Response.ok().entity(sb.toString()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the theme configuration.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
public Response get() {
|
||||||
|
JsonObject themeConfig = getThemeConfig();
|
||||||
|
JsonObjectBuilder json = Json.createObjectBuilder();
|
||||||
|
json.add("name", themeConfig.getString("name", "Sismics Docs"));
|
||||||
|
json.add("color", themeConfig.getString("color", "#263238"));
|
||||||
|
json.add("css", themeConfig.getString("css", ""));
|
||||||
|
return Response.ok().entity(json.build()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the theme configuration.
|
||||||
|
*
|
||||||
|
* @param color Theme color
|
||||||
|
* @param name Application name
|
||||||
|
* @param css Custom CSS
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
@POST
|
||||||
|
public Response theme(@FormParam("color") String color,
|
||||||
|
@FormParam("name") String name,
|
||||||
|
@FormParam("css") String css) {
|
||||||
|
if (!authenticate()) {
|
||||||
|
throw new ForbiddenClientException();
|
||||||
|
}
|
||||||
|
checkBaseFunction(BaseFunction.ADMIN);
|
||||||
|
|
||||||
|
// Validate input data
|
||||||
|
ValidationUtil.validateHexColor(color, "color", true);
|
||||||
|
name = ValidationUtil.validateLength(name, "name", 3, 30, true);
|
||||||
|
|
||||||
|
// Update the JSON
|
||||||
|
JsonObjectBuilder json = getMutableThemeConfig();
|
||||||
|
if (Strings.isNullOrEmpty(color)) {
|
||||||
|
json.add("color", JsonValue.NULL);
|
||||||
|
} else {
|
||||||
|
json.add("color", color);
|
||||||
|
}
|
||||||
|
if (Strings.isNullOrEmpty(name)) {
|
||||||
|
json.add("name", JsonValue.NULL);
|
||||||
|
} else {
|
||||||
|
json.add("name", name);
|
||||||
|
}
|
||||||
|
json.add("css", JsonUtil.nullable(css));
|
||||||
|
|
||||||
|
// Persist the new configuration
|
||||||
|
ConfigDao configDao = new ConfigDao();
|
||||||
|
configDao.update(ConfigType.THEME, json.build().toString());
|
||||||
|
|
||||||
|
// Always return OK
|
||||||
|
JsonObjectBuilder response = Json.createObjectBuilder()
|
||||||
|
.add("status", "ok");
|
||||||
|
return Response.ok().entity(response.build()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("image/{type: logo|background}")
|
||||||
|
@Consumes("multipart/form-data")
|
||||||
|
public Response images(@PathParam("type") String type,
|
||||||
|
@FormDataParam("image") FormDataBodyPart imageBodyPart) {
|
||||||
|
if (!authenticate()) {
|
||||||
|
throw new ForbiddenClientException();
|
||||||
|
}
|
||||||
|
checkBaseFunction(BaseFunction.ADMIN);
|
||||||
|
if (imageBodyPart == null) {
|
||||||
|
throw new ClientException("NoImageProvided", "An image is required");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only a background or a logo is handled
|
||||||
|
java.nio.file.Path filePath = DirectoryUtil.getThemeDirectory().resolve(type);
|
||||||
|
|
||||||
|
// Copy the image to the theme directory
|
||||||
|
try (InputStream inputStream = imageBodyPart.getValueAs(InputStream.class)) {
|
||||||
|
Files.copy(inputStream, filePath, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ServerException("CopyError", "Error copying the image to the theme directory", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response.ok().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Produces("image/*")
|
||||||
|
@Path("image/{type: logo|background}")
|
||||||
|
public Response getImage(@PathParam("type") final String type) {
|
||||||
|
final java.nio.file.Path filePath = DirectoryUtil.getThemeDirectory().resolve(type);
|
||||||
|
|
||||||
|
// Copy the image to the response output
|
||||||
|
return Response.ok(new StreamingOutput() {
|
||||||
|
@Override
|
||||||
|
public void write(OutputStream outputStream) throws IOException, WebApplicationException {
|
||||||
|
InputStream inputStream = null;
|
||||||
|
try {
|
||||||
|
if (Files.exists(filePath)) {
|
||||||
|
inputStream = Files.newInputStream(filePath);
|
||||||
|
} else {
|
||||||
|
inputStream = getClass().getResource("/image/" + (type.equals(LOGO_IMAGE) ? "logo.png" : "background.jpg")).openStream();
|
||||||
|
}
|
||||||
|
ByteStreams.copy(inputStream, outputStream);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (inputStream != null) {
|
||||||
|
inputStream.close();
|
||||||
|
}
|
||||||
|
outputStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.header("Content-Type", "image/*")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the theme configuration object.
|
||||||
|
*
|
||||||
|
* @return Theme configuration
|
||||||
|
*/
|
||||||
|
private JsonObject getThemeConfig() {
|
||||||
|
ConfigDao configDao = new ConfigDao();
|
||||||
|
Config themeConfig = configDao.getById(ConfigType.THEME);
|
||||||
|
if (themeConfig == null) {
|
||||||
|
return Json.createObjectBuilder().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
try (JsonReader reader = Json.createReader(new StringReader(themeConfig.getValue()))) {
|
||||||
|
return reader.readObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a mutable theme configuration.
|
||||||
|
*
|
||||||
|
* @return Json builder
|
||||||
|
*/
|
||||||
|
private JsonObjectBuilder getMutableThemeConfig() {
|
||||||
|
JsonObject themeConfig = getThemeConfig();
|
||||||
|
JsonObjectBuilder json = Json.createObjectBuilder();
|
||||||
|
|
||||||
|
for (Map.Entry<String, JsonValue> entry : themeConfig.entrySet()) {
|
||||||
|
json.add(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
}
|
@ -99,7 +99,7 @@ public class UserResource extends BaseResource {
|
|||||||
user.setPassword(password);
|
user.setPassword(password);
|
||||||
user.setEmail(email);
|
user.setEmail(email);
|
||||||
user.setStorageQuota(storageQuota);
|
user.setStorageQuota(storageQuota);
|
||||||
user.setStorageCurrent(0l);
|
user.setStorageCurrent(0L);
|
||||||
try {
|
try {
|
||||||
user.setPrivateKey(EncryptionUtil.generatePrivateKey());
|
user.setPrivateKey(EncryptionUtil.generatePrivateKey());
|
||||||
} catch (NoSuchAlgorithmException e) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
@ -678,7 +678,7 @@ public class UserResource extends BaseResource {
|
|||||||
UserDao userDao = new UserDao();
|
UserDao userDao = new UserDao();
|
||||||
User user = userDao.getActiveByUsername(principal.getName());
|
User user = userDao.getActiveByUsername(principal.getName());
|
||||||
user.setTotpKey(key.getKey());
|
user.setTotpKey(key.getKey());
|
||||||
user = userDao.update(user, principal.getId());
|
userDao.update(user, principal.getId());
|
||||||
|
|
||||||
JsonObjectBuilder response = Json.createObjectBuilder()
|
JsonObjectBuilder response = Json.createObjectBuilder()
|
||||||
.add("secret", key.getKey());
|
.add("secret", key.getKey());
|
||||||
|
@ -1,26 +1,18 @@
|
|||||||
package com.sismics.docs.rest.resource;
|
package com.sismics.docs.rest.resource;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.json.Json;
|
|
||||||
import javax.json.JsonArrayBuilder;
|
|
||||||
import javax.json.JsonObjectBuilder;
|
|
||||||
import javax.ws.rs.DELETE;
|
|
||||||
import javax.ws.rs.FormParam;
|
|
||||||
import javax.ws.rs.GET;
|
|
||||||
import javax.ws.rs.POST;
|
|
||||||
import javax.ws.rs.PUT;
|
|
||||||
import javax.ws.rs.Path;
|
|
||||||
import javax.ws.rs.PathParam;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import javax.ws.rs.core.Response.Status;
|
|
||||||
|
|
||||||
import com.sismics.docs.core.dao.jpa.VocabularyDao;
|
import com.sismics.docs.core.dao.jpa.VocabularyDao;
|
||||||
import com.sismics.docs.core.model.jpa.Vocabulary;
|
import com.sismics.docs.core.model.jpa.Vocabulary;
|
||||||
import com.sismics.docs.rest.constant.BaseFunction;
|
import com.sismics.docs.rest.constant.BaseFunction;
|
||||||
import com.sismics.rest.exception.ForbiddenClientException;
|
import com.sismics.rest.exception.ForbiddenClientException;
|
||||||
import com.sismics.rest.util.ValidationUtil;
|
import com.sismics.rest.util.ValidationUtil;
|
||||||
|
|
||||||
|
import javax.json.Json;
|
||||||
|
import javax.json.JsonArrayBuilder;
|
||||||
|
import javax.json.JsonObjectBuilder;
|
||||||
|
import javax.ws.rs.*;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vocabulary REST resources.
|
* Vocabulary REST resources.
|
||||||
*
|
*
|
||||||
@ -58,7 +50,7 @@ public class VocabularyResource extends BaseResource {
|
|||||||
*
|
*
|
||||||
* @param name Name
|
* @param name Name
|
||||||
* @param value Value
|
* @param value Value
|
||||||
* @param order Order
|
* @param orderStr Order
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
@PUT
|
@PUT
|
||||||
@ -96,9 +88,10 @@ public class VocabularyResource extends BaseResource {
|
|||||||
/**
|
/**
|
||||||
* Update a vocabulary.
|
* Update a vocabulary.
|
||||||
*
|
*
|
||||||
|
* @param id ID
|
||||||
* @param name Name
|
* @param name Name
|
||||||
* @param value Value
|
* @param value Value
|
||||||
* @param order Order
|
* @param orderStr Order
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
@POST
|
@POST
|
||||||
@ -127,7 +120,7 @@ public class VocabularyResource extends BaseResource {
|
|||||||
VocabularyDao vocabularyDao = new VocabularyDao();
|
VocabularyDao vocabularyDao = new VocabularyDao();
|
||||||
Vocabulary vocabulary = vocabularyDao.getById(id);
|
Vocabulary vocabulary = vocabularyDao.getById(id);
|
||||||
if (vocabulary == null) {
|
if (vocabulary == null) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the vocabulary
|
// Update the vocabulary
|
||||||
@ -169,7 +162,7 @@ public class VocabularyResource extends BaseResource {
|
|||||||
VocabularyDao vocabularyDao = new VocabularyDao();
|
VocabularyDao vocabularyDao = new VocabularyDao();
|
||||||
Vocabulary vocabulary = vocabularyDao.getById(id);
|
Vocabulary vocabulary = vocabularyDao.getById(id);
|
||||||
if (vocabulary == null) {
|
if (vocabulary == null) {
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the vocabulary
|
// Delete the vocabulary
|
||||||
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
@ -93,7 +93,7 @@ module.exports = function(grunt) {
|
|||||||
},
|
},
|
||||||
replace: {
|
replace: {
|
||||||
dist: {
|
dist: {
|
||||||
src: ['dist/docs.min.js', 'dist/share.min.js', 'dist/**/*.html'],
|
src: ['dist/docs.min.js', 'dist/share.min.js', 'dist/**/*.html', 'dist/style/style.min.css'],
|
||||||
overwrite: true,
|
overwrite: true,
|
||||||
replacements: [{
|
replacements: [{
|
||||||
from: '../api',
|
from: '../api',
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
"grunt-contrib-less": "~0.9.0",
|
"grunt-contrib-less": "~0.9.0",
|
||||||
"grunt-remove": "~0.1.0",
|
"grunt-remove": "~0.1.0",
|
||||||
"grunt-ngmin": "0.0.3",
|
"grunt-ngmin": "0.0.3",
|
||||||
"grunt-text-replace": "~0.3.11"
|
"grunt-text-replace": "~0.3.11",
|
||||||
|
"protractor": "~3.2.2",
|
||||||
|
"selenium": "~2.20.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ angular.module('docs',
|
|||||||
})
|
})
|
||||||
.state('tag', {
|
.state('tag', {
|
||||||
url: '/tag',
|
url: '/tag',
|
||||||
|
abstract: true,
|
||||||
views: {
|
views: {
|
||||||
'page': {
|
'page': {
|
||||||
templateUrl: 'partial/docs/tag.html',
|
templateUrl: 'partial/docs/tag.html',
|
||||||
@ -33,6 +34,23 @@ angular.module('docs',
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.state('tag.default', {
|
||||||
|
url: '',
|
||||||
|
views: {
|
||||||
|
'tag': {
|
||||||
|
templateUrl: 'partial/docs/tag.default.html'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.state('tag.edit', {
|
||||||
|
url: '/:id',
|
||||||
|
views: {
|
||||||
|
'tag': {
|
||||||
|
templateUrl: 'partial/docs/tag.edit.html',
|
||||||
|
controller: 'TagEdit'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
.state('settings', {
|
.state('settings', {
|
||||||
url: '/settings',
|
url: '/settings',
|
||||||
abstract: true,
|
abstract: true,
|
||||||
@ -88,6 +106,15 @@ angular.module('docs',
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.state('settings.theme', {
|
||||||
|
url: '/theme',
|
||||||
|
views: {
|
||||||
|
'settings': {
|
||||||
|
templateUrl: 'partial/docs/settings.theme.html',
|
||||||
|
controller: 'SettingsTheme'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
.state('settings.user', {
|
.state('settings.user', {
|
||||||
url: '/user',
|
url: '/user',
|
||||||
views: {
|
views: {
|
||||||
@ -255,6 +282,7 @@ angular.module('docs',
|
|||||||
})
|
})
|
||||||
.state('user', {
|
.state('user', {
|
||||||
url: '/user',
|
url: '/user',
|
||||||
|
abstract: true,
|
||||||
views: {
|
views: {
|
||||||
'page': {
|
'page': {
|
||||||
templateUrl: 'partial/docs/usergroup.html',
|
templateUrl: 'partial/docs/usergroup.html',
|
||||||
@ -262,6 +290,14 @@ angular.module('docs',
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.state('user.default', {
|
||||||
|
url: '',
|
||||||
|
views: {
|
||||||
|
'sub': {
|
||||||
|
templateUrl: 'partial/docs/usergroup.default.html'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
.state('user.profile', {
|
.state('user.profile', {
|
||||||
url: '/:username',
|
url: '/:username',
|
||||||
views: {
|
views: {
|
||||||
@ -273,6 +309,7 @@ angular.module('docs',
|
|||||||
})
|
})
|
||||||
.state('group', {
|
.state('group', {
|
||||||
url: '/group',
|
url: '/group',
|
||||||
|
abstract: true,
|
||||||
views: {
|
views: {
|
||||||
'page': {
|
'page': {
|
||||||
templateUrl: 'partial/docs/usergroup.html',
|
templateUrl: 'partial/docs/usergroup.html',
|
||||||
@ -280,6 +317,14 @@ angular.module('docs',
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.state('group.default', {
|
||||||
|
url: '',
|
||||||
|
views: {
|
||||||
|
'sub': {
|
||||||
|
templateUrl: 'partial/docs/usergroup.default.html'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
.state('group.profile', {
|
.state('group.profile', {
|
||||||
url: '/:name',
|
url: '/:name',
|
||||||
views: {
|
views: {
|
||||||
@ -289,7 +334,6 @@ angular.module('docs',
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Configuring Restangular
|
// Configuring Restangular
|
||||||
RestangularProvider.setBaseUrl('../api');
|
RestangularProvider.setBaseUrl('../api');
|
||||||
|
|
||||||
@ -336,10 +380,15 @@ angular.module('docs',
|
|||||||
/**
|
/**
|
||||||
* Application initialization.
|
* Application initialization.
|
||||||
*/
|
*/
|
||||||
.run(function($rootScope, $state, $stateParams) {
|
.run(function($rootScope, $state, $stateParams, Restangular) {
|
||||||
$rootScope.$state = $state;
|
$rootScope.$state = $state;
|
||||||
$rootScope.$stateParams = $stateParams;
|
$rootScope.$stateParams = $stateParams;
|
||||||
$rootScope.pageTitle = 'Sismics Docs';
|
|
||||||
|
// Fetch the current theme configuration
|
||||||
|
$rootScope.appName = '';
|
||||||
|
Restangular.one('theme').get().then(function(data) {
|
||||||
|
$rootScope.appName = data.name;
|
||||||
|
});
|
||||||
})
|
})
|
||||||
/**
|
/**
|
||||||
* Redirection support for ui-router.
|
* Redirection support for ui-router.
|
||||||
@ -372,3 +421,7 @@ angular.module('docs',
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (location.search.indexOf("protractor") > -1) {
|
||||||
|
window.name = 'NG_DEFER_BOOTSTRAP!';
|
||||||
|
}
|
@ -3,95 +3,11 @@
|
|||||||
/**
|
/**
|
||||||
* Document view permissions controller.
|
* Document view permissions controller.
|
||||||
*/
|
*/
|
||||||
angular.module('docs').controller('DocumentViewPermissions', function ($scope, $stateParams, Restangular, $q) {
|
angular.module('docs').controller('DocumentViewPermissions', function($scope) {
|
||||||
// Watch for ACLs change and group them for easy displaying
|
// Watch for ACLs change and group them for easy displaying
|
||||||
$scope.$watch('document.acls', function(acls) {
|
$scope.$watch('document.inherited_acls', function(acls) {
|
||||||
$scope.acls = _.groupBy(acls, function(acl) {
|
$scope.inheritedAcls = _.groupBy(acls, function(acl) {
|
||||||
return acl.id;
|
return acl.id;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initialize add ACL
|
|
||||||
$scope.acl = { perm: 'READ' };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete an ACL.
|
|
||||||
*/
|
|
||||||
$scope.deleteAcl = function(acl) {
|
|
||||||
Restangular.one('acl/' + $stateParams.id + '/' + acl.perm + '/' + acl.id, null).remove().then(function () {
|
|
||||||
$scope.document.acls = _.reject($scope.document.acls, function(s) {
|
|
||||||
return angular.equals(acl, s);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an ACL.
|
|
||||||
*/
|
|
||||||
$scope.addAcl = function() {
|
|
||||||
// Compute ACLs to add
|
|
||||||
$scope.acl.source = $stateParams.id;
|
|
||||||
var acls = [];
|
|
||||||
if ($scope.acl.perm == 'READWRITE') {
|
|
||||||
acls = [{
|
|
||||||
source: $stateParams.id,
|
|
||||||
target: $scope.acl.target.name,
|
|
||||||
perm: 'READ',
|
|
||||||
type: $scope.acl.target.type
|
|
||||||
}, {
|
|
||||||
source: $stateParams.id,
|
|
||||||
target: $scope.acl.target.name,
|
|
||||||
perm: 'WRITE',
|
|
||||||
type: $scope.acl.target.type
|
|
||||||
}];
|
|
||||||
} else {
|
|
||||||
acls = [{
|
|
||||||
source: $stateParams.id,
|
|
||||||
target: $scope.acl.target.name,
|
|
||||||
perm: $scope.acl.perm,
|
|
||||||
type: $scope.acl.target.type
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add ACLs
|
|
||||||
_.each(acls, function(acl) {
|
|
||||||
Restangular.one('acl').put(acl).then(function(acl) {
|
|
||||||
if (_.isUndefined(acl.id)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$scope.document.acls.push(acl);
|
|
||||||
$scope.document.acls = angular.copy($scope.document.acls);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Reset form
|
|
||||||
$scope.acl = { perm: 'READ' };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Auto-complete on ACL target.
|
|
||||||
*/
|
|
||||||
$scope.getTargetAclTypeahead = function($viewValue) {
|
|
||||||
var deferred = $q.defer();
|
|
||||||
Restangular.one('acl/target/search')
|
|
||||||
.get({
|
|
||||||
search: $viewValue
|
|
||||||
}).then(function(data) {
|
|
||||||
var output = [];
|
|
||||||
|
|
||||||
// Add the type to use later
|
|
||||||
output.push.apply(output, _.map(data.users, function(user) {
|
|
||||||
user.type = 'USER';
|
|
||||||
return user;
|
|
||||||
}));
|
|
||||||
output.push.apply(output, _.map(data.groups, function(group) {
|
|
||||||
group.type = 'GROUP';
|
|
||||||
return group;
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Send the data to the typeahead directive
|
|
||||||
deferred.resolve(output, true);
|
|
||||||
});
|
|
||||||
return deferred.promise;
|
|
||||||
};
|
|
||||||
});
|
});
|
@ -0,0 +1,53 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Settings theme page controller.
|
||||||
|
*/
|
||||||
|
angular.module('docs').controller('SettingsTheme', function($scope, $rootScope, Restangular) {
|
||||||
|
// Fetch the current theme configuration
|
||||||
|
Restangular.one('theme').get().then(function(data) {
|
||||||
|
$scope.theme = data;
|
||||||
|
$rootScope.appName = $scope.theme.name;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update the theme
|
||||||
|
$scope.update = function() {
|
||||||
|
$scope.theme.name = $scope.theme.name.length == 0 ? 'Sismics Docs' : $scope.theme.name;
|
||||||
|
Restangular.one('theme').post('', $scope.theme).then(function() {
|
||||||
|
var stylesheet = $('#theme-stylesheet')[0];
|
||||||
|
stylesheet.href = stylesheet.href.replace(/\?.*|$/, '?' + new Date().getTime());
|
||||||
|
$rootScope.appName = $scope.theme.name;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send an image
|
||||||
|
$scope.sendingImage = false;
|
||||||
|
$scope.sendImage = function(type, image) {
|
||||||
|
// Build the payload
|
||||||
|
var formData = new FormData();
|
||||||
|
formData.append('image', image);
|
||||||
|
|
||||||
|
// Send the file
|
||||||
|
var done = function() {
|
||||||
|
$scope.$apply(function() {
|
||||||
|
$scope.sendingImage = false;
|
||||||
|
$scope[type] = null;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
$scope.sendingImage = true;
|
||||||
|
$.ajax({
|
||||||
|
type: 'PUT',
|
||||||
|
url: '../api/theme/image/' + type,
|
||||||
|
data: formData,
|
||||||
|
cache: false,
|
||||||
|
contentType: false,
|
||||||
|
processData: false,
|
||||||
|
success: function() {
|
||||||
|
done();
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
@ -3,35 +3,19 @@
|
|||||||
/**
|
/**
|
||||||
* Tag controller.
|
* Tag controller.
|
||||||
*/
|
*/
|
||||||
angular.module('docs').controller('Tag', function($scope, $dialog, Tag, Restangular) {
|
angular.module('docs').controller('Tag', function($scope, $dialog, Restangular, $state) {
|
||||||
$scope.tag = { name: '', color: '#3a87ad' };
|
$scope.tag = { name: '', color: '#3a87ad' };
|
||||||
|
|
||||||
// Retrieve tags
|
// Retrieve tags
|
||||||
Tag.tags().then(function(data) {
|
Restangular.one('tag/list').get().then(function(data) {
|
||||||
$scope.tags = data.tags;
|
$scope.tags = data.tags;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Retrieve tag stats
|
|
||||||
Restangular.one('tag/stats').get().then(function(data) {
|
|
||||||
$scope.stats = data.stats;
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns total number of document from tag stats.
|
* Display a tag.
|
||||||
*/
|
*/
|
||||||
$scope.getStatCount = function() {
|
$scope.viewTag = function(id) {
|
||||||
return _.reduce($scope.stats, function(memo, stat) {
|
$state.go('tag.edit', { id: id });
|
||||||
return memo + stat.count
|
|
||||||
}, 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate a tag name for duplicate.
|
|
||||||
*/
|
|
||||||
$scope.validateDuplicate = function(name) {
|
|
||||||
return !_.find($scope.tags, function(tag) {
|
|
||||||
return tag.name == name;
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,21 +49,4 @@ angular.module('docs').controller('Tag', function($scope, $dialog, Tag, Restangu
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a tag.
|
|
||||||
*/
|
|
||||||
$scope.updateTag = function(tag) {
|
|
||||||
// Update the server
|
|
||||||
return Restangular.one('tag', tag.id).post('', tag).then(function () {
|
|
||||||
// Update the stat object
|
|
||||||
var stat = _.find($scope.stats, function (t) {
|
|
||||||
return tag.id == t.id;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (stat) {
|
|
||||||
_.extend(stat, tag);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
});
|
@ -0,0 +1,26 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tag edit controller.
|
||||||
|
*/
|
||||||
|
angular.module('docs').controller('TagEdit', function($scope, $stateParams, Restangular) {
|
||||||
|
// Retrieve the tag
|
||||||
|
Restangular.one('tag', $stateParams.id).get().then(function(data) {
|
||||||
|
$scope.tag = data;
|
||||||
|
|
||||||
|
// Replace the tag from the list with this reference
|
||||||
|
_.each($scope.tags, function(tag, i) {
|
||||||
|
if (tag.id == $scope.tag.id) {
|
||||||
|
$scope.tags[i] = $scope.tag;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a tag.
|
||||||
|
*/
|
||||||
|
$scope.edit = function() {
|
||||||
|
// Update the server
|
||||||
|
Restangular.one('tag', $scope.tag.id).post('', $scope.tag);
|
||||||
|
};
|
||||||
|
});
|
112
docs-web/src/main/webapp/src/app/docs/directive/AclEdit.js
Normal file
112
docs-web/src/main/webapp/src/app/docs/directive/AclEdit.js
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ACL edit directive.
|
||||||
|
*/
|
||||||
|
angular.module('docs').directive('aclEdit', function() {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
templateUrl: 'partial/docs/directive.acledit.html',
|
||||||
|
replace: true,
|
||||||
|
scope: {
|
||||||
|
source: '=',
|
||||||
|
acls: '=',
|
||||||
|
writable: '=',
|
||||||
|
creator: '='
|
||||||
|
},
|
||||||
|
controller: function($scope, Restangular, $q) {
|
||||||
|
// Watch for ACLs change and group them for easy displaying
|
||||||
|
$scope.$watch('acls', function(acls) {
|
||||||
|
$scope.groupedAcls = _.groupBy(acls, function(acl) {
|
||||||
|
return acl.id;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize add ACL
|
||||||
|
$scope.acl = { perm: 'READ' };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete an ACL.
|
||||||
|
*/
|
||||||
|
$scope.deleteAcl = function(acl) {
|
||||||
|
Restangular.one('acl/' + $scope.source + '/' + acl.perm + '/' + acl.id, null).remove().then(function () {
|
||||||
|
$scope.acls = _.reject($scope.acls, function(s) {
|
||||||
|
return angular.equals(acl, s);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an ACL.
|
||||||
|
*/
|
||||||
|
$scope.addAcl = function() {
|
||||||
|
// Compute ACLs to add
|
||||||
|
$scope.acl.source = $scope.source;
|
||||||
|
var acls = [];
|
||||||
|
if ($scope.acl.perm == 'READWRITE') {
|
||||||
|
acls = [{
|
||||||
|
source: $scope.source,
|
||||||
|
target: $scope.acl.target.name,
|
||||||
|
perm: 'READ',
|
||||||
|
type: $scope.acl.target.type
|
||||||
|
}, {
|
||||||
|
source: $scope.source,
|
||||||
|
target: $scope.acl.target.name,
|
||||||
|
perm: 'WRITE',
|
||||||
|
type: $scope.acl.target.type
|
||||||
|
}];
|
||||||
|
} else {
|
||||||
|
acls = [{
|
||||||
|
source: $scope.source,
|
||||||
|
target: $scope.acl.target.name,
|
||||||
|
perm: $scope.acl.perm,
|
||||||
|
type: $scope.acl.target.type
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add ACLs
|
||||||
|
_.each(acls, function(acl) {
|
||||||
|
Restangular.one('acl').put(acl).then(function(acl) {
|
||||||
|
if (_.isUndefined(acl.id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$scope.acls.push(acl);
|
||||||
|
$scope.acls = angular.copy($scope.acls);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Reset form
|
||||||
|
$scope.acl = { perm: 'READ' };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-complete on ACL target.
|
||||||
|
*/
|
||||||
|
$scope.getTargetAclTypeahead = function($viewValue) {
|
||||||
|
var deferred = $q.defer();
|
||||||
|
Restangular.one('acl/target/search')
|
||||||
|
.get({
|
||||||
|
search: $viewValue
|
||||||
|
}).then(function(data) {
|
||||||
|
var output = [];
|
||||||
|
|
||||||
|
// Add the type to use later
|
||||||
|
output.push.apply(output, _.map(data.users, function(user) {
|
||||||
|
user.type = 'USER';
|
||||||
|
return user;
|
||||||
|
}));
|
||||||
|
output.push.apply(output, _.map(data.groups, function(group) {
|
||||||
|
group.type = 'GROUP';
|
||||||
|
return group;
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Send the data to the typeahead directive
|
||||||
|
deferred.resolve(output, true);
|
||||||
|
});
|
||||||
|
return deferred.promise;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
link: function(scope, element, attr, ctrl) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
@ -10,12 +10,11 @@ angular.module('docs').directive('file', function() {
|
|||||||
replace: true,
|
replace: true,
|
||||||
require: 'ngModel',
|
require: 'ngModel',
|
||||||
link: function(scope, element, attr, ctrl) {
|
link: function(scope, element, attr, ctrl) {
|
||||||
var listener = function() {
|
element.bind('change', function() {
|
||||||
scope.$apply(function() {
|
scope.$apply(function() {
|
||||||
attr.multiple ? ctrl.$setViewValue(element[0].files) : ctrl.$setViewValue(element[0].files[0]);
|
attr.multiple ? ctrl.$setViewValue(element[0].files) : ctrl.$setViewValue(element[0].files[0]);
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
element.bind('change', listener);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
@ -1,62 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inline edition directive.
|
|
||||||
* Thanks to http://jsfiddle.net/joshdmiller/NDFHg/
|
|
||||||
*/
|
|
||||||
angular.module('docs').directive('inlineEdit', function() {
|
|
||||||
return {
|
|
||||||
restrict: 'E',
|
|
||||||
scope: {
|
|
||||||
value: '=',
|
|
||||||
editCallback: '&onEdit'
|
|
||||||
},
|
|
||||||
template: '<span ng-click="edit()" ng-bind="value"></span><input type="text" class="form-control" ng-model="value" />',
|
|
||||||
link: function (scope, element, attrs) {
|
|
||||||
// Let's get a reference to the input element, as we'll want to reference it.
|
|
||||||
var inputElement = angular.element(element.children()[1]);
|
|
||||||
var el = inputElement[0];
|
|
||||||
|
|
||||||
// This directive should have a set class so we can style it.
|
|
||||||
element.addClass('inline-edit');
|
|
||||||
|
|
||||||
// Initially, we're not editing.
|
|
||||||
scope.editing = false;
|
|
||||||
|
|
||||||
// ng-click handler to activate edit-in-place
|
|
||||||
scope.edit = function () {
|
|
||||||
scope.editing = true;
|
|
||||||
scope.oldValue = el.value;
|
|
||||||
|
|
||||||
// We control display through a class on the directive itself. See the CSS.
|
|
||||||
element.addClass('active');
|
|
||||||
|
|
||||||
// And we must focus the element.
|
|
||||||
// `angular.element()` provides a chainable array, like jQuery so to access a native DOM function,
|
|
||||||
// we have to reference the first element in the array.
|
|
||||||
el.focus();
|
|
||||||
el.selectionStart = 0;
|
|
||||||
el.selectionEnd = el.value.length;
|
|
||||||
};
|
|
||||||
|
|
||||||
// When we leave the input, we're done editing.
|
|
||||||
inputElement.on('blur', function() {
|
|
||||||
scope.editing = false;
|
|
||||||
element.removeClass('active');
|
|
||||||
|
|
||||||
// Invoke parent scope callback
|
|
||||||
if (scope.editCallback && scope.oldValue != el.value) {
|
|
||||||
scope.$apply(function() {
|
|
||||||
if (scope.value) {
|
|
||||||
scope.editCallback().then(null, function() {
|
|
||||||
scope.value = scope.oldValue;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
scope.value = scope.oldValue;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
@ -13,9 +13,9 @@ angular.module('docs').directive('selectTag', function() {
|
|||||||
ref: '@',
|
ref: '@',
|
||||||
ngDisabled: '='
|
ngDisabled: '='
|
||||||
},
|
},
|
||||||
controller: function($scope, Tag) {
|
controller: function($scope, Restangular) {
|
||||||
// Retrieve tags
|
// Retrieve tags
|
||||||
Tag.tags().then(function(data) {
|
Restangular.one('tag/list').get().then(function(data) {
|
||||||
$scope.allTags = data.tags;
|
$scope.allTags = data.tags;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ angular.module('docs').directive('selectTag', function() {
|
|||||||
if ($event) {
|
if ($event) {
|
||||||
$event.preventDefault();
|
$event.preventDefault();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a tag.
|
* Remove a tag.
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tag service.
|
|
||||||
*/
|
|
||||||
angular.module('docs').factory('Tag', function(Restangular) {
|
|
||||||
var tags = null;
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Returns tags.
|
|
||||||
* @param force If true, force reloading data
|
|
||||||
*/
|
|
||||||
tags: function(force) {
|
|
||||||
return Restangular.one('tag/list').get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -95,7 +95,13 @@ angular.module('share',
|
|||||||
/**
|
/**
|
||||||
* Application initialization.
|
* Application initialization.
|
||||||
*/
|
*/
|
||||||
.run(function($rootScope, $state, $stateParams) {
|
.run(function($rootScope, $state, $stateParams, Restangular) {
|
||||||
$rootScope.$state = $state;
|
$rootScope.$state = $state;
|
||||||
$rootScope.$stateParams = $stateParams;
|
$rootScope.$stateParams = $stateParams;
|
||||||
|
|
||||||
|
// Fetch the current theme configuration
|
||||||
|
$rootScope.appName = '';
|
||||||
|
Restangular.one('theme').get().then(function(data) {
|
||||||
|
$rootScope.appName = data.name;
|
||||||
|
});
|
||||||
});
|
});
|
@ -1,15 +1,16 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html ng-app="docs">
|
<html ng-app="docs">
|
||||||
<head>
|
<head>
|
||||||
<title ng-bind-template="{{ pageTitle }}">Sismics Docs</title>
|
<title ng-bind-template="{{ appName }}">Sismics Docs</title>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<link rel="shortcut icon" href="favicon.png" />
|
<link rel="shortcut icon" href="../api/theme/image/logo" />
|
||||||
<!-- ref:css style/style.min.css -->
|
<!-- ref:css style/style.min.css -->
|
||||||
<link rel="stylesheet" href="style/bootstrap.css" type="text/css" />
|
<link rel="stylesheet" href="style/bootstrap.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="style/colorpicker.css" type="text/css" />
|
<link rel="stylesheet" href="style/colorpicker.css" type="text/css" />
|
||||||
<link rel="stylesheet/less" href="style/main.less" type="text/css" />
|
<link rel="stylesheet/less" href="style/main.less" type="text/css" />
|
||||||
<!-- endref -->
|
<!-- endref -->
|
||||||
|
<link rel="stylesheet" href="../api/theme/stylesheet" type="text/css" id="theme-stylesheet" />
|
||||||
<!-- ref:remove -->
|
<!-- ref:remove -->
|
||||||
<script>
|
<script>
|
||||||
less = {
|
less = {
|
||||||
@ -54,10 +55,12 @@
|
|||||||
<script src="app/docs/controller/document/FileModalView.js" type="text/javascript"></script>
|
<script src="app/docs/controller/document/FileModalView.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/controller/Login.js" type="text/javascript"></script>
|
<script src="app/docs/controller/Login.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/controller/tag/Tag.js" type="text/javascript"></script>
|
<script src="app/docs/controller/tag/Tag.js" type="text/javascript"></script>
|
||||||
|
<script src="app/docs/controller/tag/TagEdit.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/controller/Navigation.js" type="text/javascript"></script>
|
<script src="app/docs/controller/Navigation.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/controller/settings/Settings.js" type="text/javascript"></script>
|
<script src="app/docs/controller/settings/Settings.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/controller/settings/SettingsDefault.js" type="text/javascript"></script>
|
<script src="app/docs/controller/settings/SettingsDefault.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/controller/settings/SettingsAccount.js" type="text/javascript"></script>
|
<script src="app/docs/controller/settings/SettingsAccount.js" type="text/javascript"></script>
|
||||||
|
<script src="app/docs/controller/settings/SettingsTheme.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/controller/settings/SettingsSecurity.js" type="text/javascript"></script>
|
<script src="app/docs/controller/settings/SettingsSecurity.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/controller/settings/SettingsSecurityModalDisableTotp.js" type="text/javascript"></script>
|
<script src="app/docs/controller/settings/SettingsSecurityModalDisableTotp.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/controller/settings/SettingsSession.js" type="text/javascript"></script>
|
<script src="app/docs/controller/settings/SettingsSession.js" type="text/javascript"></script>
|
||||||
@ -71,7 +74,6 @@
|
|||||||
<script src="app/docs/controller/usergroup/UserProfile.js" type="text/javascript"></script>
|
<script src="app/docs/controller/usergroup/UserProfile.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/controller/usergroup/GroupProfile.js" type="text/javascript"></script>
|
<script src="app/docs/controller/usergroup/GroupProfile.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/service/User.js" type="text/javascript"></script>
|
<script src="app/docs/service/User.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/service/Tag.js" type="text/javascript"></script>
|
|
||||||
<script src="app/docs/filter/Newline.js" type="text/javascript"></script>
|
<script src="app/docs/filter/Newline.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/filter/Shorten.js" type="text/javascript"></script>
|
<script src="app/docs/filter/Shorten.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/filter/Filesize.js" type="text/javascript"></script>
|
<script src="app/docs/filter/Filesize.js" type="text/javascript"></script>
|
||||||
@ -79,9 +81,9 @@
|
|||||||
<script src="app/docs/directive/SelectTag.js" type="text/javascript"></script>
|
<script src="app/docs/directive/SelectTag.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/directive/SelectRelation.js" type="text/javascript"></script>
|
<script src="app/docs/directive/SelectRelation.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/directive/AuditLog.js" type="text/javascript"></script>
|
<script src="app/docs/directive/AuditLog.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/directive/InlineEdit.js" type="text/javascript"></script>
|
|
||||||
<script src="app/docs/directive/ImgError.js" type="text/javascript"></script>
|
<script src="app/docs/directive/ImgError.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/directive/Acl.js" type="text/javascript"></script>
|
<script src="app/docs/directive/Acl.js" type="text/javascript"></script>
|
||||||
|
<script src="app/docs/directive/AclEdit.js" type="text/javascript"></script>
|
||||||
<!-- endref -->
|
<!-- endref -->
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -97,10 +99,10 @@
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="hidden-xs navbar-text navbar-logo">
|
<div class="hidden-xs navbar-text navbar-logo">
|
||||||
<img src="favicon.png" />
|
<img src="../api/theme/image/logo" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a class="navbar-brand" href="#"> Sismics Docs</a>
|
<a class="navbar-brand" href="#"> {{ appName }}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="collapse navbar-collapse" collapse="isCollapsed">
|
<div class="collapse navbar-collapse" collapse="isCollapsed">
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
<div>
|
||||||
|
<table class="table">
|
||||||
|
<tr>
|
||||||
|
<th style="width: 40%">For</th>
|
||||||
|
<th style="width: 40%">Permission</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr ng-repeat="(id, acl) in groupedAcls">
|
||||||
|
<td><acl data="acl[0]"></acl></td>
|
||||||
|
<td>
|
||||||
|
<span class="label label-default" style="margin-right: 6px;" ng-repeat="a in acl | orderBy: 'perm'">
|
||||||
|
{{ a.perm }}
|
||||||
|
<span ng-show="(creator != a.name && a.type == 'USER' || a.type != 'USER') && writable"
|
||||||
|
class="glyphicon glyphicon-remove pointer"
|
||||||
|
ng-click="deleteAcl(a)"></span>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div ng-show="writable">
|
||||||
|
<h4>Add a permission</h4>
|
||||||
|
|
||||||
|
<form name="aclForm" class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label" for="inputTarget">For</label>
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<input required ng-maxlength="50" class="form-control" type="text" id="inputTarget"
|
||||||
|
placeholder="Search a user or group" name="target" ng-model="acl.target" autocomplete="off"
|
||||||
|
typeahead="target as target.name for target in getTargetAclTypeahead($viewValue) | filter: $viewValue"
|
||||||
|
typeahead-template-url="partial/docs/directive.typeahead.acl.html"
|
||||||
|
typeahead-wait-ms="200" />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<span class="btn btn-primary" ng-if="acl.target.type" ng-click="acl.target = null">
|
||||||
|
<acl data="acl.target"></acl>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class=" col-sm-2 control-label" for="inputPermission">Permission</label>
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<select class="form-control" ng-model="acl.perm" id="inputPermission">
|
||||||
|
<option value="READ">Can read</option>
|
||||||
|
<option value="READWRITE">Can edit</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
<button type="submit" class="btn btn-primary" ng-disabled="!acl.target.type" ng-click="addAcl()">
|
||||||
|
<span class="glyphicon glyphicon-plus"></span>
|
||||||
|
Add
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -1 +1,3 @@
|
|||||||
|
<p class="well-sm">Every actions on this document are logged here.</p>
|
||||||
|
|
||||||
<audit-log logs="logs" />
|
<audit-log logs="logs" />
|
@ -1,59 +1,37 @@
|
|||||||
<table class="table">
|
<p class="well-sm">Permissions can be applied directly to this document, or can come from <a href="#/tag">tags</a>.</p>
|
||||||
|
|
||||||
|
<div class="well" ng-show="document.inherited_acls.length > 0">
|
||||||
|
<h3>Permissions inherited by tags</h3>
|
||||||
|
|
||||||
|
<table class="table">
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width: 40%">For</th>
|
<th style="width: 30%">From</th>
|
||||||
<th style="width: 40%">Permission</th>
|
<th style="width: 30%">For</th>
|
||||||
|
<th style="width: 30%">Permission</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr ng-repeat="(id, acl) in acls">
|
<tr ng-repeat="(id, acl) in inheritedAcls">
|
||||||
|
<td>
|
||||||
|
<a href="#/tag/{{ acl[0].source_id }}">
|
||||||
|
<span class="glyphicon glyphicon-tags"></span>
|
||||||
|
{{ acl[0].source_name }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
<td><acl data="acl[0]"></acl></td>
|
<td><acl data="acl[0]"></acl></td>
|
||||||
<td>
|
<td>
|
||||||
<span class="label label-default" style="margin-right: 6px;" ng-repeat="a in acl | orderBy: 'perm'">
|
<span class="label label-default" style="margin-right: 6px;" ng-repeat="a in acl | orderBy: 'perm'">
|
||||||
{{ a.perm }}
|
{{ a.perm }}
|
||||||
<span ng-show="(document.creator != a.name && a.type == 'USER' || a.type != 'USER') && document.writable"
|
|
||||||
class="glyphicon glyphicon-remove pointer"
|
|
||||||
ng-click="deleteAcl(a)"></span>
|
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
<div ng-show="document.writable">
|
|
||||||
<h4>Add a permission</h4>
|
<div class="well">
|
||||||
|
<h3>Permissions on this document</h3>
|
||||||
<form name="aclForm" class="form-horizontal">
|
|
||||||
<div class="form-group">
|
<acl-edit source="document.id"
|
||||||
<label class="col-sm-2 control-label" for="inputTarget">For</label>
|
acls="document.acls"
|
||||||
<div class="col-sm-3">
|
writable="document.writable"
|
||||||
<input required ng-maxlength="50" class="form-control" type="text" id="inputTarget"
|
creator="document.creator"></acl-edit>
|
||||||
placeholder="Search a user or group" name="target" ng-model="acl.target" autocomplete="off"
|
|
||||||
typeahead="target as target.name for target in getTargetAclTypeahead($viewValue) | filter: $viewValue"
|
|
||||||
typeahead-template-url="partial/docs/directive.typeahead.acl.html"
|
|
||||||
typeahead-wait-ms="200" />
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-4">
|
|
||||||
<span class="btn btn-primary" ng-if="acl.target.type" ng-click="acl.target = null">
|
|
||||||
<acl data="acl.target"></acl>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label class=" col-sm-2 control-label" for="inputPermission">Permission</label>
|
|
||||||
<div class="col-sm-3">
|
|
||||||
<select class="form-control" ng-model="acl.perm" id="inputPermission">
|
|
||||||
<option value="READ">Can read</option>
|
|
||||||
<option value="READWRITE">Can edit</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="col-sm-offset-2 col-sm-10">
|
|
||||||
<button type="submit" class="btn btn-primary" ng-disabled="!acl.target.type" ng-click="addAcl()">
|
|
||||||
<span class="glyphicon glyphicon-plus"></span>
|
|
||||||
Add
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
@ -15,6 +15,7 @@
|
|||||||
<a class="list-group-item" ng-show="isAdmin" ng-class="{active: $uiRoute}" ui-route="/settings/user.*" href="#/settings/user">Users</a>
|
<a class="list-group-item" ng-show="isAdmin" ng-class="{active: $uiRoute}" ui-route="/settings/user.*" href="#/settings/user">Users</a>
|
||||||
<a class="list-group-item" ng-show="isAdmin" ng-class="{active: $uiRoute}" ui-route="/settings/group.*" href="#/settings/group">Groups</a>
|
<a class="list-group-item" ng-show="isAdmin" ng-class="{active: $uiRoute}" ui-route="/settings/group.*" href="#/settings/group">Groups</a>
|
||||||
<a class="list-group-item" ng-show="isAdmin" ng-class="{active: $uiRoute}" ui-route="/settings/vocabulary.*" href="#/settings/vocabulary">Vocabularies</a>
|
<a class="list-group-item" ng-show="isAdmin" ng-class="{active: $uiRoute}" ui-route="/settings/vocabulary.*" href="#/settings/vocabulary">Vocabularies</a>
|
||||||
|
<a class="list-group-item" ng-show="isAdmin" ng-class="{active: $uiRoute}" ui-route="/settings/theme" href="#/settings/theme">Theme</a>
|
||||||
<a class="list-group-item" ng-show="isAdmin" ng-class="{active: $uiRoute}" ui-route="/settings/log" href="#/settings/log">Server logs</a>
|
<a class="list-group-item" ng-show="isAdmin" ng-class="{active: $uiRoute}" ui-route="/settings/log" href="#/settings/log">Server logs</a>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
<div ng-if="!user.totp_enabled">
|
<div ng-if="!user.totp_enabled">
|
||||||
<p>
|
<p>
|
||||||
Two-factor authentication allows you to add a layer of security on your <strong>Sismics Docs</strong> account.<br/>
|
Two-factor authentication allows you to add a layer of security on your <strong>{{ appName }}</strong> account.<br/>
|
||||||
Before activating this feature, make sure you have a TOTP-compatible app on your phone:
|
Before activating this feature, make sure you have a TOTP-compatible app on your phone:
|
||||||
</p>
|
</p>
|
||||||
<ul>
|
<ul>
|
||||||
@ -17,7 +17,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
<p>
|
<p>
|
||||||
Those applications automatically generate a validation code that changes after a certain period of time.<br/>
|
Those applications automatically generate a validation code that changes after a certain period of time.<br/>
|
||||||
You will be required to enter this validation code each time you login on <strong>Sismics Docs</strong>.
|
You will be required to enter this validation code each time you login on <strong>{{ appName }}</strong>.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<button class="btn btn-primary" ng-click="enableTotp()">Enable two-factor authentication</button>
|
<button class="btn btn-primary" ng-click="enableTotp()">Enable two-factor authentication</button>
|
||||||
@ -34,7 +34,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
Two-factor authentication is enabled on your account.<br/>
|
Two-factor authentication is enabled on your account.<br/>
|
||||||
Each time you login on <strong>Sismics Docs</strong>, you will be asked a validation code from your configured phone app.<br/>
|
Each time you login on <strong>{{ appName }}</strong>, you will be asked a validation code from your configured phone app.<br/>
|
||||||
If you loose your phone, you will not be able to login into your account but active sessions will allow you to regenerate a secrey key.
|
If you loose your phone, you will not be able to login into your account but active sessions will allow you to regenerate a secrey key.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
|
@ -0,0 +1,63 @@
|
|||||||
|
<h1>Theme <small>customization</small></h1>
|
||||||
|
<form class="form-horizontal" name="editColorForm" novalidate>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label" for="inputName">Application name</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<input type="text" class="form-control"
|
||||||
|
id="inputName" ng-model="theme.name" ng-blur="update()" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label" for="inputColor">Main color</label>
|
||||||
|
<div class="col-sm-1">
|
||||||
|
<span colorpicker class="btn btn-default" id="inputColor" on-hide="update()"
|
||||||
|
data-color="" ng-model="theme.color" ng-style="{ 'background': theme.color }"> </span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label" for="inputCss">Custom CSS</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<textarea class="form-control" rows="6" placeholder="Custom CSS to add after the main stylesheet"
|
||||||
|
id="inputCss" ng-model="theme.css" ng-blur="update()"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label" for="inputLogo">Logo</label>
|
||||||
|
<div class="col-sm-2">
|
||||||
|
<file accept="image/gif,image/png,image/jpg,image/jpeg"
|
||||||
|
class="form-control" id="inputLogo" ng-model="logo" ng-disabled="sendingImage" />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-2">
|
||||||
|
<button class="btn btn-default" ng-click="sendImage('logo', logo)" ng-disabled="sendingImage || !logo">
|
||||||
|
<span class="glyphicon glyphicon-save"></span>
|
||||||
|
Send
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label" for="inputBackground">Background image</label>
|
||||||
|
<div class="col-sm-2">
|
||||||
|
<file accept="image/gif,image/png,image/jpg,image/jpeg"
|
||||||
|
class="form-control" id="inputLogo" ng-model="background" ng-disabled="sendingImage" />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-2">
|
||||||
|
<button class="btn btn-default" ng-click="sendImage('background', background)" ng-disabled="sendingImage || !background">
|
||||||
|
<span class="glyphicon glyphicon-save"></span>
|
||||||
|
Send
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label"></label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<p class="form-control-static text-info" ng-if="sendingImage">
|
||||||
|
Uploading the image...
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
@ -0,0 +1,6 @@
|
|||||||
|
<h1>Tags</h1>
|
||||||
|
<p><strong>Tags</strong> are labels associated to documents.</p>
|
||||||
|
<p>A document can be tagged by multiple tags, and a tag can be applied to multiple documents.</p>
|
||||||
|
<p>Using the <span class="glyphicon glyphicon-pencil"></span> button, you can edit permissions on a tag.</p>
|
||||||
|
<p>If a tag can be read by another user or group, associated documents can also be read by those people.</p>
|
||||||
|
<p>For example, tag your company documents with a tag <span class="label label-info">MyCompany</span> and add the permission <strong>Read</strong> to a group <span class="btn btn-default">employees</span></p>
|
54
docs-web/src/main/webapp/src/partial/docs/tag.edit.html
Normal file
54
docs-web/src/main/webapp/src/partial/docs/tag.edit.html
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<h1>{{ tag.name }} </h1>
|
||||||
|
|
||||||
|
<div class="well col-lg-8">
|
||||||
|
<form class="form-horizontal" name="editTagForm" novalidate>
|
||||||
|
<div class="form-group" ng-class="{ 'has-error': !editTagForm.name.$valid, success: editTagForm.name.$valid }">
|
||||||
|
<label class="col-sm-2 control-label" for="inputName">Name</label>
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<input type="text" name="name" class="form-control" id="inputName"
|
||||||
|
ng-maxlength="36" required ng-model="tag.name" ui-validate="{ space: '!$value || $value.indexOf(\' \') == -1' }">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label" for="inputColor">Color</label>
|
||||||
|
|
||||||
|
<div class="col-sm-2">
|
||||||
|
<span colorpicker class="btn" data-color="" id="inputColor"
|
||||||
|
ng-model="tag.color" ng-style="{ 'background': tag.color }"> </span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label" for="inputParent">Parent</label>
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<select class="form-control" ng-model="tag.parent" id="inputParent">
|
||||||
|
<option value="" ng-selected="!tag.parent"></option>
|
||||||
|
<option ng-repeat="tag0 in tags"
|
||||||
|
ng-if="tag0.id != tag.id"
|
||||||
|
ng-selected="tag.parent == tag0.id"
|
||||||
|
value="{{ tag0.id }}">Parent: {{ tag0.name }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
<button type="submit" class="btn btn-primary" ng-click="edit()" ng-disabled="!editTagForm.$valid">
|
||||||
|
<span class="glyphicon glyphicon-pencil"></span> Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="well col-lg-8">
|
||||||
|
<p>Permissions on this tag will also be applied to documents tagged <span class="label label-info" ng-style="{ 'background': tag.color }">{{ tag.name }}</span></p>
|
||||||
|
|
||||||
|
<acl-edit source="tag.id"
|
||||||
|
acls="tag.acls"
|
||||||
|
writable="tag.writable"
|
||||||
|
creator="tag.creator"></acl-edit>
|
||||||
|
</div>
|
@ -5,10 +5,9 @@
|
|||||||
<p class="input-group" ng-class="{ 'has-error': !tagForm.name.$valid }">
|
<p class="input-group" ng-class="{ 'has-error': !tagForm.name.$valid }">
|
||||||
<span colorpicker class="input-group-addon btn btn-default" data-color="#3a87ad" ng-model="tag.color" ng-style="{ 'background': tag.color }"> </span>
|
<span colorpicker class="input-group-addon btn btn-default" data-color="#3a87ad" ng-model="tag.color" ng-style="{ 'background': tag.color }"> </span>
|
||||||
<input type="text" name="name" placeholder="New tag" class="form-control"
|
<input type="text" name="name" placeholder="New tag" class="form-control"
|
||||||
ng-maxlength="36" required ng-model="tag.name" ui-validate="{duplicate: 'validateDuplicate($value)', space: '!$value || $value.indexOf(\' \') == -1' }">
|
ng-maxlength="36" required ng-model="tag.name" ui-validate="{ space: '!$value || $value.indexOf(\' \') == -1' }">
|
||||||
<span class="input-group-addon btn btn-primary" ng-disabled="!tagForm.$valid" ng-click="addTag()">Add</span>
|
<span class="input-group-addon btn btn-primary" ng-disabled="!tagForm.$valid" ng-click="addTag()">Add</span>
|
||||||
</p>
|
</p>
|
||||||
<span class="help-block" ng-show="tagForm.name.$error.duplicate">This tag already exists</span>
|
|
||||||
<span class="help-block" ng-show="tagForm.name.$error.space">Space are not allowed</span>
|
<span class="help-block" ng-show="tagForm.name.$error.space">Space are not allowed</span>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
@ -17,36 +16,31 @@
|
|||||||
<input type="search" class="form-control" placeholder="Search" ng-model="search.name">
|
<input type="search" class="form-control" placeholder="Search" ng-model="search.name">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<table class="row table table-striped table-hover">
|
<table class="row table table-striped table-hover table-tags">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr ng-repeat="tag in tags | filter:search">
|
<tr ng-repeat="tag in tags | filter:search" class="pointer"
|
||||||
<td><inline-edit value="tag.name" on-edit="updateTag(tag)" ></inline-edit></td>
|
ng-class="{ active: $stateParams.id == tag.id }" ng-click="viewTag(tag.id)">
|
||||||
<td class="col-xs-4">
|
<td>
|
||||||
<select class="form-control" ng-model="tag.parent" ng-change="updateTag(tag)">
|
<span class="glyphicon glyphicon-tag"></span>
|
||||||
<option value="" ng-selected="!tag.parent"></option>
|
<span class="label label-info" ng-style="{ 'background': tag.color }">{{ tag.name }}</span>
|
||||||
<option ng-repeat="tag0 in tags"
|
</td>
|
||||||
ng-if="tag0.id != tag.id"
|
<td class="col-xs-1">
|
||||||
ng-selected="tag.parent == tag0.id"
|
<a href="#/tag/{{ tag.id }}" class="btn btn-primary pull-right" title="Edit tag">
|
||||||
value="{{ tag0.id }}">Parent: {{ tag0.name }}</option>
|
<span class="glyphicon glyphicon-pencil"></span>
|
||||||
</select>
|
</a>
|
||||||
|
</td>
|
||||||
|
<td class="col-xs-1">
|
||||||
|
<button class="btn btn-danger pull-right" ng-click="deleteTag(tag)" title="Delete this tag">
|
||||||
|
<span class="glyphicon glyphicon-trash"></span>
|
||||||
|
</button>
|
||||||
</td>
|
</td>
|
||||||
<td class="col-xs-1"><span colorpicker class="btn" on-hide="updateTag(tag)" data-color="" ng-model="tag.color" ng-style="{ 'background': tag.color }"> </span></td>
|
|
||||||
<td class="col-xs-1"><button class="btn btn-danger pull-right" ng-click="deleteTag(tag)"><span class="glyphicon glyphicon-trash"></span></button></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-8" ng-if="stats.length >= 0">
|
<div class="col-md-8">
|
||||||
<h1>{{ tags.length }} <small>tag{{ tags.length > 1 ? 's' : '' }}</small></h1>
|
<div ui-view="tag"></div>
|
||||||
<dl class="dl-horizontal" ng-repeat="stat in stats | orderBy: '-count'">
|
|
||||||
<dt>{{ stat.name }} <span class="badge badge-info" ng-style="{ 'background': stat.color }">{{ stat.count }}</span></dt>
|
|
||||||
<dd><progressbar value="stat.count / getStatCount() * 100" class="progress-info"></progressbar></dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-8" ng-if="!stats">
|
|
||||||
<img src="img/loader.gif" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -0,0 +1,2 @@
|
|||||||
|
<h1>Users & Groups</h1>
|
||||||
|
<p>Here you can view informations about users and groups.</p>
|
@ -1,7 +1,7 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html ng-app="share">
|
<html ng-app="share">
|
||||||
<head>
|
<head>
|
||||||
<title>Sismics Docs</title>
|
<title>{{ appName }}</title>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<link rel="shortcut icon" href="favicon.png" />
|
<link rel="shortcut icon" href="favicon.png" />
|
||||||
@ -9,6 +9,7 @@
|
|||||||
<link rel="stylesheet" href="style/bootstrap.css" type="text/css" />
|
<link rel="stylesheet" href="style/bootstrap.css" type="text/css" />
|
||||||
<link rel="stylesheet/less" href="style/main.less" type="text/css" />
|
<link rel="stylesheet/less" href="style/main.less" type="text/css" />
|
||||||
<!-- endref -->
|
<!-- endref -->
|
||||||
|
<link rel="stylesheet" href="../api/theme/stylesheet" type="text/css" />
|
||||||
<!-- ref:remove -->
|
<!-- ref:remove -->
|
||||||
<script>
|
<script>
|
||||||
less = {
|
less = {
|
||||||
@ -45,10 +46,10 @@
|
|||||||
<div class="navbar navbar-default" role="navigation">
|
<div class="navbar navbar-default" role="navigation">
|
||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
<div class="hidden-xs navbar-text navbar-logo">
|
<div class="hidden-xs navbar-text navbar-logo">
|
||||||
<img src="favicon.png" />
|
<img src="../api/theme/image/logo" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a class="navbar-brand" href="#"> Sismics Docs</a>
|
<a class="navbar-brand" href="#"> {{ appName }}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -21,6 +21,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tags list
|
||||||
|
.table-tags {
|
||||||
|
td {
|
||||||
|
vertical-align: middle !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Documents list
|
// Documents list
|
||||||
.table-documents {
|
.table-documents {
|
||||||
thead th {
|
thead th {
|
||||||
@ -156,10 +167,6 @@ input[readonly].share-link {
|
|||||||
|
|
||||||
// Pagination box
|
// Pagination box
|
||||||
.pagination-box {
|
.pagination-box {
|
||||||
pagination {
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
select {
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
width: auto;
|
width: auto;
|
||||||
@ -234,7 +241,7 @@ input[readonly].share-link {
|
|||||||
|
|
||||||
// Login
|
// Login
|
||||||
.login-box-container {
|
.login-box-container {
|
||||||
background: url('../img/background.jpg') no-repeat center;
|
background: url('../../api/theme/image/background') no-repeat center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-box {
|
.login-box {
|
||||||
|
21
docs-web/src/main/webapp/test/conf.js
Normal file
21
docs-web/src/main/webapp/test/conf.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
exports.config = {
|
||||||
|
seleniumServerJar: '../node_modules/selenium/lib/runner/selenium-server-standalone-2.20.0.jar',
|
||||||
|
framework: 'jasmine',
|
||||||
|
rootElement: 'html',
|
||||||
|
baseUrl: 'http://localhost:9999/docs-web/src/?protractor',
|
||||||
|
capabilities: {
|
||||||
|
'browserName': 'chrome'
|
||||||
|
},
|
||||||
|
|
||||||
|
specs: [
|
||||||
|
'specs/**/*.js'
|
||||||
|
],
|
||||||
|
|
||||||
|
jasmineNodeOpts: {
|
||||||
|
isVerbose: true,
|
||||||
|
showColors: true,
|
||||||
|
defaultTimeoutInterval: 30000
|
||||||
|
}
|
||||||
|
};
|
24
docs-web/src/main/webapp/test/specs/temp.js
Normal file
24
docs-web/src/main/webapp/test/specs/temp.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
describe('document', function () {
|
||||||
|
it('should create and delete a document', function () {
|
||||||
|
browser.get('');
|
||||||
|
|
||||||
|
// Login as admin
|
||||||
|
element(by.model('user.username')).sendKeys('admin');
|
||||||
|
element(by.model('user.password')).sendKeys('admin');
|
||||||
|
element(by.css('.login-box button[type="submit"]')).click();
|
||||||
|
|
||||||
|
// Create a document
|
||||||
|
element(by.partialLinkText('Add a document')).click();
|
||||||
|
element(by.model('document.title')).sendKeys('My test document');
|
||||||
|
element(by.buttonText('Add')).click();
|
||||||
|
|
||||||
|
// Open the last document
|
||||||
|
element(by.css('.table-documents tbody tr:nth-child(1)')).click();
|
||||||
|
|
||||||
|
// Delete the document
|
||||||
|
element(by.partialButtonText('Delete')).click();
|
||||||
|
element(by.partialButtonText('OK')).click();
|
||||||
|
});
|
||||||
|
});
|
@ -71,7 +71,7 @@ public class TestAclResource extends BaseJerseyTest {
|
|||||||
String acl2Id = json.getString("id");
|
String acl2Id = json.getString("id");
|
||||||
|
|
||||||
// Add an ACL WRITE for acl2 with acl1
|
// Add an ACL WRITE for acl2 with acl1
|
||||||
json = target().path("/acl").request()
|
target().path("/acl").request()
|
||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acl1Token)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acl1Token)
|
||||||
.put(Entity.form(new Form()
|
.put(Entity.form(new Form()
|
||||||
.param("source", document1Id)
|
.param("source", document1Id)
|
||||||
@ -80,7 +80,7 @@ public class TestAclResource extends BaseJerseyTest {
|
|||||||
.param("type", "USER")), JsonObject.class);
|
.param("type", "USER")), JsonObject.class);
|
||||||
|
|
||||||
// Add an ACL WRITE for acl2 with acl1 (again)
|
// Add an ACL WRITE for acl2 with acl1 (again)
|
||||||
json = target().path("/acl").request()
|
target().path("/acl").request()
|
||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acl1Token)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acl1Token)
|
||||||
.put(Entity.form(new Form()
|
.put(Entity.form(new Form()
|
||||||
.param("source", document1Id)
|
.param("source", document1Id)
|
||||||
@ -99,7 +99,7 @@ public class TestAclResource extends BaseJerseyTest {
|
|||||||
String aclGroup2Id = json.getString("id");
|
String aclGroup2Id = json.getString("id");
|
||||||
|
|
||||||
// Add an ACL WRITE for aclGroup2 with acl1
|
// Add an ACL WRITE for aclGroup2 with acl1
|
||||||
json = target().path("/acl").request()
|
target().path("/acl").request()
|
||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acl1Token)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acl1Token)
|
||||||
.put(Entity.form(new Form()
|
.put(Entity.form(new Form()
|
||||||
.param("source", document1Id)
|
.param("source", document1Id)
|
||||||
@ -234,9 +234,9 @@ public class TestAclResource extends BaseJerseyTest {
|
|||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acl1Token)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acl1Token)
|
||||||
.get(JsonObject.class);
|
.get(JsonObject.class);
|
||||||
JsonArray users = json.getJsonArray("users");
|
JsonArray users = json.getJsonArray("users");
|
||||||
Assert.assertEquals(2, users.size());
|
Assert.assertTrue(users.size() > 0);
|
||||||
JsonArray groups = json.getJsonArray("groups");
|
JsonArray groups = json.getJsonArray("groups");
|
||||||
Assert.assertEquals(1, groups.size());
|
Assert.assertTrue(groups.size() > 0);
|
||||||
|
|
||||||
// Search target list (admin)
|
// Search target list (admin)
|
||||||
json = target().path("/acl/target/search")
|
json = target().path("/acl/target/search")
|
||||||
@ -249,4 +249,187 @@ public class TestAclResource extends BaseJerseyTest {
|
|||||||
groups = json.getJsonArray("groups");
|
groups = json.getJsonArray("groups");
|
||||||
Assert.assertEquals(1, groups.size());
|
Assert.assertEquals(1, groups.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAclTags() {
|
||||||
|
// Login acltag1
|
||||||
|
clientUtil.createUser("acltag1");
|
||||||
|
String acltag1Token = clientUtil.login("acltag1");
|
||||||
|
|
||||||
|
// Login acltag2
|
||||||
|
clientUtil.createUser("acltag2");
|
||||||
|
String acltag2Token = clientUtil.login("acltag2");
|
||||||
|
|
||||||
|
// Create tag1 with acltag1
|
||||||
|
JsonObject json = target().path("/tag").request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag1Token)
|
||||||
|
.put(Entity.form(new Form()
|
||||||
|
.param("name", "AclTag1")
|
||||||
|
.param("color", "#ff0000")), JsonObject.class);
|
||||||
|
String tag1Id = json.getString("id");
|
||||||
|
Assert.assertNotNull(tag1Id);
|
||||||
|
|
||||||
|
// Create document1 with acltag1 tagged with tag1
|
||||||
|
json = target().path("/document").request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag1Token)
|
||||||
|
.put(Entity.form(new Form()
|
||||||
|
.param("title", "My super document 1")
|
||||||
|
.param("tags", tag1Id)
|
||||||
|
.param("language", "eng")), JsonObject.class);
|
||||||
|
String document1Id = json.getString("id");
|
||||||
|
|
||||||
|
// acltag2 cannot see document1
|
||||||
|
Response response = target().path("/document/" + document1Id).request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token)
|
||||||
|
.get();
|
||||||
|
Assert.assertEquals(Status.NOT_FOUND.getStatusCode(), response.getStatus());
|
||||||
|
|
||||||
|
// acltag2 cannot see any tag
|
||||||
|
json = target().path("/tag/list").request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token)
|
||||||
|
.get(JsonObject.class);
|
||||||
|
JsonArray tags = json.getJsonArray("tags");
|
||||||
|
Assert.assertEquals(0, tags.size());
|
||||||
|
|
||||||
|
// acltag2 cannot see tag1
|
||||||
|
response = target().path("/tag/" + tag1Id).request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token)
|
||||||
|
.get();
|
||||||
|
Assert.assertEquals(Status.NOT_FOUND.getStatusCode(), response.getStatus());
|
||||||
|
|
||||||
|
// acltag2 cannot see any document
|
||||||
|
json = target().path("/document/list")
|
||||||
|
.queryParam("sort_column", 3)
|
||||||
|
.queryParam("asc", true)
|
||||||
|
.request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token)
|
||||||
|
.get(JsonObject.class);
|
||||||
|
JsonArray documents = json.getJsonArray("documents");
|
||||||
|
Assert.assertEquals(0, documents.size());
|
||||||
|
|
||||||
|
// acltag2 cannot edit tag1
|
||||||
|
response = target().path("/tag/" + tag1Id).request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token)
|
||||||
|
.post(Entity.form(new Form()
|
||||||
|
.param("name", "AclTag1")
|
||||||
|
.param("color", "#ff0000")));
|
||||||
|
Assert.assertEquals(Status.NOT_FOUND.getStatusCode(), response.getStatus());
|
||||||
|
|
||||||
|
// acltag2 cannot edit document1
|
||||||
|
response = target().path("/document/" + document1Id).request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token)
|
||||||
|
.post(Entity.form(new Form()
|
||||||
|
.param("title", "My super document 1")
|
||||||
|
.param("tags", tag1Id)
|
||||||
|
.param("language", "eng")));
|
||||||
|
Assert.assertEquals(Status.FORBIDDEN.getStatusCode(), response.getStatus());
|
||||||
|
|
||||||
|
// Add an ACL READ for acltag2 with acltag1 on tag1
|
||||||
|
target().path("/acl").request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag1Token)
|
||||||
|
.put(Entity.form(new Form()
|
||||||
|
.param("source", tag1Id)
|
||||||
|
.param("perm", "READ")
|
||||||
|
.param("target", "acltag2")
|
||||||
|
.param("type", "USER")), JsonObject.class);
|
||||||
|
|
||||||
|
// acltag2 can see tag1
|
||||||
|
json = target().path("/tag/" + tag1Id).request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token)
|
||||||
|
.get(JsonObject.class);
|
||||||
|
Assert.assertFalse(json.getBoolean("writable"));
|
||||||
|
Assert.assertEquals(3, json.getJsonArray("acls").size());
|
||||||
|
|
||||||
|
// acltag2 still cannot edit tag1
|
||||||
|
response = target().path("/tag/" + tag1Id).request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token)
|
||||||
|
.post(Entity.form(new Form()
|
||||||
|
.param("name", "AclTag1")
|
||||||
|
.param("color", "#ff0000")));
|
||||||
|
Assert.assertEquals(Status.NOT_FOUND.getStatusCode(), response.getStatus());
|
||||||
|
|
||||||
|
// acltag2 still cannot edit document1
|
||||||
|
response = target().path("/document/" + document1Id).request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token)
|
||||||
|
.post(Entity.form(new Form()
|
||||||
|
.param("title", "My super document 1")
|
||||||
|
.param("tags", tag1Id)
|
||||||
|
.param("language", "eng")));
|
||||||
|
Assert.assertEquals(Status.FORBIDDEN.getStatusCode(), response.getStatus());
|
||||||
|
|
||||||
|
// acltag2 can see document1 with tag1 (non-writable)
|
||||||
|
json = target().path("/document/" + document1Id).request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token)
|
||||||
|
.get(JsonObject.class);
|
||||||
|
tags = json.getJsonArray("tags");
|
||||||
|
Assert.assertEquals(1, tags.size());
|
||||||
|
Assert.assertFalse(json.getBoolean("writable"));
|
||||||
|
Assert.assertEquals(tag1Id, tags.getJsonObject(0).getString("id"));
|
||||||
|
JsonArray inheritedAcls = json.getJsonArray("inherited_acls");
|
||||||
|
Assert.assertEquals(3, inheritedAcls.size());
|
||||||
|
Assert.assertEquals("AclTag1", inheritedAcls.getJsonObject(0).getString("source_name"));
|
||||||
|
Assert.assertEquals(tag1Id, inheritedAcls.getJsonObject(0).getString("source_id"));
|
||||||
|
|
||||||
|
// acltag2 can see tag1
|
||||||
|
json = target().path("/tag/list").request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token)
|
||||||
|
.get(JsonObject.class);
|
||||||
|
tags = json.getJsonArray("tags");
|
||||||
|
Assert.assertEquals(1, tags.size());
|
||||||
|
Assert.assertEquals(tag1Id, tags.getJsonObject(0).getString("id"));
|
||||||
|
|
||||||
|
// acltag2 can see exactly one document
|
||||||
|
json = target().path("/document/list")
|
||||||
|
.queryParam("sort_column", 3)
|
||||||
|
.queryParam("asc", true)
|
||||||
|
.request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token)
|
||||||
|
.get(JsonObject.class);
|
||||||
|
documents = json.getJsonArray("documents");
|
||||||
|
Assert.assertEquals(1, documents.size());
|
||||||
|
|
||||||
|
// Add an ACL WRITE for acltag2 with acltag1 on tag1
|
||||||
|
target().path("/acl").request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag1Token)
|
||||||
|
.put(Entity.form(new Form()
|
||||||
|
.param("source", tag1Id)
|
||||||
|
.param("perm", "WRITE")
|
||||||
|
.param("target", "acltag2")
|
||||||
|
.param("type", "USER")), JsonObject.class);
|
||||||
|
|
||||||
|
// acltag2 can see document1 with tag1 (writable)
|
||||||
|
json = target().path("/document/" + document1Id).request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token)
|
||||||
|
.get(JsonObject.class);
|
||||||
|
tags = json.getJsonArray("tags");
|
||||||
|
Assert.assertEquals(1, tags.size());
|
||||||
|
Assert.assertTrue(json.getBoolean("writable"));
|
||||||
|
Assert.assertEquals(tag1Id, tags.getJsonObject(0).getString("id"));
|
||||||
|
inheritedAcls = json.getJsonArray("inherited_acls");
|
||||||
|
Assert.assertEquals(4, inheritedAcls.size());
|
||||||
|
Assert.assertEquals("AclTag1", inheritedAcls.getJsonObject(0).getString("source_name"));
|
||||||
|
Assert.assertEquals(tag1Id, inheritedAcls.getJsonObject(0).getString("source_id"));
|
||||||
|
|
||||||
|
// acltag2 can see and edit tag1
|
||||||
|
json = target().path("/tag/" + tag1Id).request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token)
|
||||||
|
.get(JsonObject.class);
|
||||||
|
Assert.assertTrue(json.getBoolean("writable"));
|
||||||
|
Assert.assertEquals(4, json.getJsonArray("acls").size());
|
||||||
|
|
||||||
|
// acltag2 can edit tag1
|
||||||
|
target().path("/tag/" + tag1Id).request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token)
|
||||||
|
.post(Entity.form(new Form()
|
||||||
|
.param("name", "AclTag1")
|
||||||
|
.param("color", "#ff0000")), JsonObject.class);
|
||||||
|
|
||||||
|
// acltag2 can edit document1
|
||||||
|
target().path("/document/" + document1Id).request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token)
|
||||||
|
.post(Entity.form(new Form()
|
||||||
|
.param("title", "My super document 1")
|
||||||
|
.param("tags", tag1Id)
|
||||||
|
.param("language", "eng")), JsonObject.class);
|
||||||
|
}
|
||||||
}
|
}
|
@ -2,11 +2,17 @@ package com.sismics.docs.rest;
|
|||||||
|
|
||||||
import javax.json.JsonArray;
|
import javax.json.JsonArray;
|
||||||
import javax.json.JsonObject;
|
import javax.json.JsonObject;
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
import javax.persistence.EntityTransaction;
|
||||||
import javax.ws.rs.client.Entity;
|
import javax.ws.rs.client.Entity;
|
||||||
import javax.ws.rs.core.Form;
|
import javax.ws.rs.core.Form;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.Response.Status;
|
import javax.ws.rs.core.Response.Status;
|
||||||
|
|
||||||
|
import com.sismics.docs.core.constant.PermType;
|
||||||
|
import com.sismics.docs.core.dao.jpa.AclDao;
|
||||||
|
import com.sismics.util.context.ThreadLocalContext;
|
||||||
|
import com.sismics.util.jpa.EMF;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@ -57,6 +63,35 @@ public class TestAppResource extends BaseJerseyTest {
|
|||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken)
|
||||||
.post(Entity.form(new Form()));
|
.post(Entity.form(new Form()));
|
||||||
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
|
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
|
||||||
|
|
||||||
|
// Create a tag
|
||||||
|
json = target().path("/tag").request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken)
|
||||||
|
.put(Entity.form(new Form()
|
||||||
|
.param("name", "Tag4")
|
||||||
|
.param("color", "#00ff00")), JsonObject.class);
|
||||||
|
String tagId = json.getString("id");
|
||||||
|
|
||||||
|
// Init transactional context
|
||||||
|
EntityManager em = EMF.get().createEntityManager();
|
||||||
|
ThreadLocalContext context = ThreadLocalContext.get();
|
||||||
|
context.setEntityManager(em);
|
||||||
|
EntityTransaction tx = em.getTransaction();
|
||||||
|
tx.begin();
|
||||||
|
|
||||||
|
// Remove base ACLs
|
||||||
|
AclDao aclDao = new AclDao();
|
||||||
|
aclDao.delete(tagId, PermType.READ, "admin", "admin");
|
||||||
|
aclDao.delete(tagId, PermType.WRITE, "admin", "admin");
|
||||||
|
Assert.assertEquals(0, aclDao.getBySourceId(tagId).size());
|
||||||
|
tx.commit();
|
||||||
|
|
||||||
|
// Add base ACLs to tags
|
||||||
|
response = target().path("/app/batch/tag_acls").request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken)
|
||||||
|
.post(Entity.form(new Form()));
|
||||||
|
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
|
||||||
|
Assert.assertEquals(2, aclDao.getBySourceId(tagId).size());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -87,7 +87,7 @@ public class TestDocumentResource extends BaseJerseyTest {
|
|||||||
Assert.assertNotNull(document2Id);
|
Assert.assertNotNull(document2Id);
|
||||||
|
|
||||||
// Add a file
|
// Add a file
|
||||||
String file1Id = null;
|
String file1Id;
|
||||||
try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) {
|
try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) {
|
||||||
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "Einstein-Roosevelt-letter.png");
|
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "Einstein-Roosevelt-letter.png");
|
||||||
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
|
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
|
||||||
@ -103,7 +103,7 @@ public class TestDocumentResource extends BaseJerseyTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Share this document
|
// Share this document
|
||||||
json = target().path("/share").request()
|
target().path("/share").request()
|
||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token)
|
||||||
.put(Entity.form(new Form().param("id", document1Id)), JsonObject.class);
|
.put(Entity.form(new Form().param("id", document1Id)), JsonObject.class);
|
||||||
|
|
||||||
@ -148,7 +148,7 @@ public class TestDocumentResource extends BaseJerseyTest {
|
|||||||
Assert.assertNotNull(document3Id);
|
Assert.assertNotNull(document3Id);
|
||||||
|
|
||||||
// Add a file
|
// Add a file
|
||||||
String file3Id = null;
|
String file3Id;
|
||||||
try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) {
|
try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) {
|
||||||
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "Einstein-Roosevelt-letter.png");
|
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "Einstein-Roosevelt-letter.png");
|
||||||
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
|
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
|
||||||
@ -393,7 +393,7 @@ public class TestDocumentResource extends BaseJerseyTest {
|
|||||||
Assert.assertNotNull(document1Id);
|
Assert.assertNotNull(document1Id);
|
||||||
|
|
||||||
// Add a PDF file
|
// Add a PDF file
|
||||||
String file1Id = null;
|
String file1Id;
|
||||||
try (InputStream is = Resources.getResource("file/document.odt").openStream()) {
|
try (InputStream is = Resources.getResource("file/document.odt").openStream()) {
|
||||||
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "document.odt");
|
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "document.odt");
|
||||||
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
|
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
|
||||||
@ -452,7 +452,7 @@ public class TestDocumentResource extends BaseJerseyTest {
|
|||||||
Assert.assertNotNull(document1Id);
|
Assert.assertNotNull(document1Id);
|
||||||
|
|
||||||
// Add a PDF file
|
// Add a PDF file
|
||||||
String file1Id = null;
|
String file1Id;
|
||||||
try (InputStream is = Resources.getResource("file/document.docx").openStream()) {
|
try (InputStream is = Resources.getResource("file/document.docx").openStream()) {
|
||||||
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "document.docx");
|
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "document.docx");
|
||||||
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
|
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
|
||||||
@ -511,7 +511,7 @@ public class TestDocumentResource extends BaseJerseyTest {
|
|||||||
Assert.assertNotNull(document1Id);
|
Assert.assertNotNull(document1Id);
|
||||||
|
|
||||||
// Add a PDF file
|
// Add a PDF file
|
||||||
String file1Id = null;
|
String file1Id;
|
||||||
try (InputStream is = Resources.getResource("file/wikipedia.pdf").openStream()) {
|
try (InputStream is = Resources.getResource("file/wikipedia.pdf").openStream()) {
|
||||||
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "wikipedia.pdf");
|
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "wikipedia.pdf");
|
||||||
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
|
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
|
||||||
|
@ -56,7 +56,7 @@ public class TestFileResource extends BaseJerseyTest {
|
|||||||
Assert.assertNotNull(document1Id);
|
Assert.assertNotNull(document1Id);
|
||||||
|
|
||||||
// Add a file
|
// Add a file
|
||||||
String file1Id = null;
|
String file1Id;
|
||||||
try (InputStream is = Resources.getResource("file/PIA00452.jpg").openStream()) {
|
try (InputStream is = Resources.getResource("file/PIA00452.jpg").openStream()) {
|
||||||
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "PIA00452.jpg");
|
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "PIA00452.jpg");
|
||||||
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
|
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
|
||||||
@ -68,12 +68,12 @@ public class TestFileResource extends BaseJerseyTest {
|
|||||||
MediaType.MULTIPART_FORM_DATA_TYPE), JsonObject.class);
|
MediaType.MULTIPART_FORM_DATA_TYPE), JsonObject.class);
|
||||||
file1Id = json.getString("id");
|
file1Id = json.getString("id");
|
||||||
Assert.assertNotNull(file1Id);
|
Assert.assertNotNull(file1Id);
|
||||||
Assert.assertEquals(163510l, json.getJsonNumber("size").longValue());
|
Assert.assertEquals(163510L, json.getJsonNumber("size").longValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a file
|
// Add a file
|
||||||
String file2Id = null;
|
String file2Id;
|
||||||
try (InputStream is = Resources.getResource("file/PIA00452.jpg").openStream()) {
|
try (InputStream is = Resources.getResource("file/PIA00452.jpg").openStream()) {
|
||||||
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "PIA00452.jpg");
|
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "PIA00452.jpg");
|
||||||
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
|
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
|
||||||
@ -136,11 +136,11 @@ public class TestFileResource extends BaseJerseyTest {
|
|||||||
JsonArray files = json.getJsonArray("files");
|
JsonArray files = json.getJsonArray("files");
|
||||||
Assert.assertEquals(2, files.size());
|
Assert.assertEquals(2, files.size());
|
||||||
Assert.assertEquals(file1Id, files.getJsonObject(0).getString("id"));
|
Assert.assertEquals(file1Id, files.getJsonObject(0).getString("id"));
|
||||||
Assert.assertEquals(163510l, files.getJsonObject(0).getJsonNumber("size").longValue());
|
Assert.assertEquals(163510L, files.getJsonObject(0).getJsonNumber("size").longValue());
|
||||||
Assert.assertEquals(file2Id, files.getJsonObject(1).getString("id"));
|
Assert.assertEquals(file2Id, files.getJsonObject(1).getString("id"));
|
||||||
|
|
||||||
// Reorder files
|
// Reorder files
|
||||||
json = target().path("/file/reorder").request()
|
target().path("/file/reorder").request()
|
||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, file1Token)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, file1Token)
|
||||||
.post(Entity.form(new Form()
|
.post(Entity.form(new Form()
|
||||||
.param("id", document1Id)
|
.param("id", document1Id)
|
||||||
@ -210,7 +210,7 @@ public class TestFileResource extends BaseJerseyTest {
|
|||||||
String file2Token = clientUtil.login("file2");
|
String file2Token = clientUtil.login("file2");
|
||||||
|
|
||||||
// Add a file
|
// Add a file
|
||||||
String file1Id = null;
|
String file1Id;
|
||||||
try (InputStream is = Resources.getResource("file/PIA00452.jpg").openStream()) {
|
try (InputStream is = Resources.getResource("file/PIA00452.jpg").openStream()) {
|
||||||
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "PIA00452.jpg");
|
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "PIA00452.jpg");
|
||||||
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
|
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
|
||||||
@ -251,7 +251,7 @@ public class TestFileResource extends BaseJerseyTest {
|
|||||||
Assert.assertNotNull(document1Id);
|
Assert.assertNotNull(document1Id);
|
||||||
|
|
||||||
// Attach a file to a document
|
// Attach a file to a document
|
||||||
json = target().path("/file/" + file1Id).request()
|
target().path("/file/" + file1Id).request()
|
||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, file2Token)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, file2Token)
|
||||||
.post(Entity.form(new Form()
|
.post(Entity.form(new Form()
|
||||||
.param("id", document1Id)), JsonObject.class);
|
.param("id", document1Id)), JsonObject.class);
|
||||||
@ -266,7 +266,7 @@ public class TestFileResource extends BaseJerseyTest {
|
|||||||
Assert.assertEquals(1, files.size());
|
Assert.assertEquals(1, files.size());
|
||||||
|
|
||||||
// Add a file
|
// Add a file
|
||||||
String file2Id = null;
|
String file2Id;
|
||||||
try (InputStream is0 = Resources.getResource("file/PIA00452.jpg").openStream()) {
|
try (InputStream is0 = Resources.getResource("file/PIA00452.jpg").openStream()) {
|
||||||
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is0, "PIA00452.jpg");
|
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is0, "PIA00452.jpg");
|
||||||
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
|
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
|
||||||
@ -300,7 +300,7 @@ public class TestFileResource extends BaseJerseyTest {
|
|||||||
String fileQuotaToken = clientUtil.login("file_quota");
|
String fileQuotaToken = clientUtil.login("file_quota");
|
||||||
|
|
||||||
// Add a file (292641 bytes large)
|
// Add a file (292641 bytes large)
|
||||||
String file1Id = null;
|
String file1Id;
|
||||||
try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) {
|
try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) {
|
||||||
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "Einstein-Roosevelt-letter.png");
|
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "Einstein-Roosevelt-letter.png");
|
||||||
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
|
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
|
||||||
@ -319,7 +319,7 @@ public class TestFileResource extends BaseJerseyTest {
|
|||||||
JsonObject json = target().path("/user").request()
|
JsonObject json = target().path("/user").request()
|
||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaToken)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaToken)
|
||||||
.get(JsonObject.class);
|
.get(JsonObject.class);
|
||||||
Assert.assertEquals(292641l, json.getJsonNumber("storage_current").longValue());
|
Assert.assertEquals(292641L, json.getJsonNumber("storage_current").longValue());
|
||||||
|
|
||||||
// Add a file (292641 bytes large)
|
// Add a file (292641 bytes large)
|
||||||
try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) {
|
try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) {
|
||||||
@ -338,7 +338,7 @@ public class TestFileResource extends BaseJerseyTest {
|
|||||||
json = target().path("/user").request()
|
json = target().path("/user").request()
|
||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaToken)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaToken)
|
||||||
.get(JsonObject.class);
|
.get(JsonObject.class);
|
||||||
Assert.assertEquals(585282l, json.getJsonNumber("storage_current").longValue());
|
Assert.assertEquals(585282L, json.getJsonNumber("storage_current").longValue());
|
||||||
|
|
||||||
// Add a file (292641 bytes large)
|
// Add a file (292641 bytes large)
|
||||||
try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) {
|
try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) {
|
||||||
@ -357,7 +357,7 @@ public class TestFileResource extends BaseJerseyTest {
|
|||||||
json = target().path("/user").request()
|
json = target().path("/user").request()
|
||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaToken)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaToken)
|
||||||
.get(JsonObject.class);
|
.get(JsonObject.class);
|
||||||
Assert.assertEquals(877923l, json.getJsonNumber("storage_current").longValue());
|
Assert.assertEquals(877923L, json.getJsonNumber("storage_current").longValue());
|
||||||
|
|
||||||
// Add a file (292641 bytes large)
|
// Add a file (292641 bytes large)
|
||||||
try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) {
|
try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) {
|
||||||
@ -383,6 +383,6 @@ public class TestFileResource extends BaseJerseyTest {
|
|||||||
json = target().path("/user").request()
|
json = target().path("/user").request()
|
||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaToken)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaToken)
|
||||||
.get(JsonObject.class);
|
.get(JsonObject.class);
|
||||||
Assert.assertEquals(585282l, json.getJsonNumber("storage_current").longValue());
|
Assert.assertEquals(585282L, json.getJsonNumber("storage_current").longValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -106,7 +106,7 @@ public class TestGroupResource extends BaseJerseyTest {
|
|||||||
Assert.assertEquals(1, users.size());
|
Assert.assertEquals(1, users.size());
|
||||||
|
|
||||||
// Add group1 to g112 (again)
|
// Add group1 to g112 (again)
|
||||||
json = target().path("/group/g112").request()
|
target().path("/group/g112").request()
|
||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken)
|
||||||
.put(Entity.form(new Form()
|
.put(Entity.form(new Form()
|
||||||
.param("username", "group1")), JsonObject.class);
|
.param("username", "group1")), JsonObject.class);
|
||||||
@ -145,7 +145,7 @@ public class TestGroupResource extends BaseJerseyTest {
|
|||||||
Assert.assertEquals("group1", members.getString(0));
|
Assert.assertEquals("group1", members.getString(0));
|
||||||
|
|
||||||
// Remove group1 from g12new
|
// Remove group1 from g12new
|
||||||
json = target().path("/group/g12new/group1").request()
|
target().path("/group/g12new/group1").request()
|
||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken)
|
||||||
.delete(JsonObject.class);
|
.delete(JsonObject.class);
|
||||||
|
|
||||||
@ -164,7 +164,7 @@ public class TestGroupResource extends BaseJerseyTest {
|
|||||||
Assert.assertTrue(groupList.contains("g112"));
|
Assert.assertTrue(groupList.contains("g112"));
|
||||||
|
|
||||||
// Delete group g1
|
// Delete group g1
|
||||||
json = target().path("/group/g1").request()
|
target().path("/group/g1").request()
|
||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken)
|
||||||
.delete(JsonObject.class);
|
.delete(JsonObject.class);
|
||||||
|
|
||||||
|
@ -47,6 +47,18 @@ public class TestTagResource extends BaseJerseyTest {
|
|||||||
String tag4Id = json.getString("id");
|
String tag4Id = json.getString("id");
|
||||||
Assert.assertNotNull(tag4Id);
|
Assert.assertNotNull(tag4Id);
|
||||||
|
|
||||||
|
// Get the tag
|
||||||
|
json = target().path("/tag/" + tag4Id).request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, tag1Token)
|
||||||
|
.get(JsonObject.class);
|
||||||
|
Assert.assertEquals("Tag4", json.getString("name"));
|
||||||
|
Assert.assertEquals("tag1", json.getString("creator"));
|
||||||
|
Assert.assertEquals("#00ff00", json.getString("color"));
|
||||||
|
Assert.assertEquals(tag3Id, json.getString("parent"));
|
||||||
|
Assert.assertTrue(json.getBoolean("writable"));
|
||||||
|
JsonArray acls = json.getJsonArray("acls");
|
||||||
|
Assert.assertEquals(2, acls.size());
|
||||||
|
|
||||||
// Create a tag with space (not allowed)
|
// Create a tag with space (not allowed)
|
||||||
Response response = target().path("/tag").request()
|
Response response = target().path("/tag").request()
|
||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, tag1Token)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, tag1Token)
|
||||||
@ -55,7 +67,7 @@ public class TestTagResource extends BaseJerseyTest {
|
|||||||
Assert.assertEquals(Status.BAD_REQUEST, Status.fromStatusCode(response.getStatus()));
|
Assert.assertEquals(Status.BAD_REQUEST, Status.fromStatusCode(response.getStatus()));
|
||||||
|
|
||||||
// Create a document
|
// Create a document
|
||||||
json = target().path("/document").request()
|
target().path("/document").request()
|
||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, tag1Token)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, tag1Token)
|
||||||
.put(Entity.form(new Form()
|
.put(Entity.form(new Form()
|
||||||
.param("title", "My super document 1")
|
.param("title", "My super document 1")
|
||||||
@ -115,15 +127,6 @@ public class TestTagResource extends BaseJerseyTest {
|
|||||||
Assert.assertEquals(1, tags.size());
|
Assert.assertEquals(1, tags.size());
|
||||||
Assert.assertEquals(tag4Id, tags.getJsonObject(0).getString("id"));
|
Assert.assertEquals(tag4Id, tags.getJsonObject(0).getString("id"));
|
||||||
|
|
||||||
// Get tag stats
|
|
||||||
json = target().path("/tag/stats").request()
|
|
||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, tag1Token)
|
|
||||||
.get(JsonObject.class);
|
|
||||||
JsonArray stats = json.getJsonArray("stats");
|
|
||||||
Assert.assertTrue(stats.size() == 2);
|
|
||||||
Assert.assertEquals(1, stats.getJsonObject(0).getInt("count"));
|
|
||||||
Assert.assertEquals(1, stats.getJsonObject(1).getInt("count"));
|
|
||||||
|
|
||||||
// Get all tags
|
// Get all tags
|
||||||
json = target().path("/tag/list").request()
|
json = target().path("/tag/list").request()
|
||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, tag1Token)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, tag1Token)
|
||||||
@ -150,7 +153,7 @@ public class TestTagResource extends BaseJerseyTest {
|
|||||||
Assert.assertTrue(tags.size() > 0);
|
Assert.assertTrue(tags.size() > 0);
|
||||||
Assert.assertEquals("UpdatedName", tags.getJsonObject(1).getString("name"));
|
Assert.assertEquals("UpdatedName", tags.getJsonObject(1).getString("name"));
|
||||||
Assert.assertEquals("#0000ff", tags.getJsonObject(1).getString("color"));
|
Assert.assertEquals("#0000ff", tags.getJsonObject(1).getString("color"));
|
||||||
Assert.assertEquals(JsonValue.NULL, tags.getJsonObject(1).get("parent"));
|
Assert.assertNull(tags.getJsonObject(1).get("parent"));
|
||||||
|
|
||||||
// Deletes a tag
|
// Deletes a tag
|
||||||
target().path("/tag/" + tag4Id).request()
|
target().path("/tag/" + tag4Id).request()
|
||||||
|
@ -0,0 +1,107 @@
|
|||||||
|
package com.sismics.docs.rest;
|
||||||
|
|
||||||
|
import com.google.common.io.Resources;
|
||||||
|
import com.sismics.util.filter.TokenBasedSecurityFilter;
|
||||||
|
import org.glassfish.jersey.media.multipart.FormDataMultiPart;
|
||||||
|
import org.glassfish.jersey.media.multipart.MultiPartFeature;
|
||||||
|
import org.glassfish.jersey.media.multipart.file.StreamDataBodyPart;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import javax.json.JsonObject;
|
||||||
|
import javax.ws.rs.client.Entity;
|
||||||
|
import javax.ws.rs.core.Form;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the theme resource.
|
||||||
|
*
|
||||||
|
* @author bgamard
|
||||||
|
*/
|
||||||
|
public class TestThemeResource extends BaseJerseyTest {
|
||||||
|
/**
|
||||||
|
* Test the theme resource.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testThemeResource() throws Exception {
|
||||||
|
// Login admin
|
||||||
|
String adminToken = clientUtil.login("admin", "admin", false);
|
||||||
|
|
||||||
|
// Get the stylesheet anonymously
|
||||||
|
String stylesheet = target().path("/theme/stylesheet").request()
|
||||||
|
.get(String.class);
|
||||||
|
Assert.assertTrue(stylesheet.contains("background-color: #263238;"));
|
||||||
|
|
||||||
|
// Get the theme configuration anonymously
|
||||||
|
JsonObject json = target().path("/theme").request()
|
||||||
|
.get(JsonObject.class);
|
||||||
|
Assert.assertEquals("Sismics Docs", json.getString("name"));
|
||||||
|
Assert.assertEquals("#263238", json.getString("color"));
|
||||||
|
Assert.assertEquals("", json.getString("css"));
|
||||||
|
|
||||||
|
// Update the main color as admin
|
||||||
|
target().path("/theme").request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken)
|
||||||
|
.post(Entity.form(new Form()
|
||||||
|
.param("color", "#ff0000")
|
||||||
|
.param("name", "My App")
|
||||||
|
.param("css", ".body { content: 'Custom CSS'; }")), JsonObject.class);
|
||||||
|
|
||||||
|
// Get the stylesheet anonymously
|
||||||
|
stylesheet = target().path("/theme/stylesheet").request()
|
||||||
|
.get(String.class);
|
||||||
|
Assert.assertTrue(stylesheet.contains("background-color: #ff0000;"));
|
||||||
|
Assert.assertTrue(stylesheet.contains("Custom CSS"));
|
||||||
|
|
||||||
|
// Get the theme configuration anonymously
|
||||||
|
json = target().path("/theme").request()
|
||||||
|
.get(JsonObject.class);
|
||||||
|
Assert.assertEquals("My App", json.getString("name"));
|
||||||
|
Assert.assertEquals("#ff0000", json.getString("color"));
|
||||||
|
Assert.assertEquals(".body { content: 'Custom CSS'; }", json.getString("css"));
|
||||||
|
|
||||||
|
// Get the logo
|
||||||
|
Response response = target().path("/theme/image/logo").request().get();
|
||||||
|
Assert.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
|
||||||
|
|
||||||
|
// Get the background
|
||||||
|
response = target().path("/theme/image/background").request().get();
|
||||||
|
Assert.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
|
||||||
|
|
||||||
|
// Change the logo
|
||||||
|
try (InputStream is = Resources.getResource("file/PIA00452.jpg").openStream()) {
|
||||||
|
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("image", is, "PIA00452.jpg");
|
||||||
|
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
|
||||||
|
target()
|
||||||
|
.register(MultiPartFeature.class)
|
||||||
|
.path("/theme/image/logo").request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken)
|
||||||
|
.put(Entity.entity(multiPart.bodyPart(streamDataBodyPart),
|
||||||
|
MediaType.MULTIPART_FORM_DATA_TYPE), JsonObject.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change the background
|
||||||
|
try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) {
|
||||||
|
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("image", is, "Einstein-Roosevelt-letter.png");
|
||||||
|
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
|
||||||
|
target()
|
||||||
|
.register(MultiPartFeature.class)
|
||||||
|
.path("/theme/image/background").request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken)
|
||||||
|
.put(Entity.entity(multiPart.bodyPart(streamDataBodyPart),
|
||||||
|
MediaType.MULTIPART_FORM_DATA_TYPE), JsonObject.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the logo
|
||||||
|
response = target().path("/theme/image/logo").request().get();
|
||||||
|
Assert.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
|
||||||
|
|
||||||
|
// Get the background
|
||||||
|
response = target().path("/theme/image/background").request().get();
|
||||||
|
Assert.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
|
||||||
|
}
|
||||||
|
}
|
@ -120,9 +120,9 @@
|
|||||||
</build>
|
</build>
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
<module>../docs-core</module>
|
<module>docs-core</module>
|
||||||
<module>../docs-web-common</module>
|
<module>docs-web-common</module>
|
||||||
<module>../docs-web</module>
|
<module>docs-web</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
@ -375,7 +375,8 @@
|
|||||||
<version>${fr.opensagres.xdocreport.version}</version>
|
<version>${fr.opensagres.xdocreport.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency> <!-- Servlet listener to register SPI ImageIO plugins -->
|
<!-- Servlet listener to register SPI ImageIO plugins -->
|
||||||
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.servlet</groupId>
|
<groupId>com.twelvemonkeys.servlet</groupId>
|
||||||
<artifactId>servlet</artifactId>
|
<artifactId>servlet</artifactId>
|
||||||
<version>${com.twelvemonkeys.imageio.version}</version>
|
<version>${com.twelvemonkeys.imageio.version}</version>
|
||||||
@ -389,7 +390,8 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- ImageIO plugins -->
|
<!-- ImageIO plugins -->
|
||||||
<dependency> <!-- Permissive JPEG plugin -->
|
<!-- Permissive JPEG plugin -->
|
||||||
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio-jpeg</artifactId>
|
<artifactId>imageio-jpeg</artifactId>
|
||||||
<version>${com.twelvemonkeys.imageio.version}</version>
|
<version>${com.twelvemonkeys.imageio.version}</version>
|
Loading…
Reference in New Issue
Block a user