# HG changeset patch # User ymh # Date 1389807387 -3600 # Node ID 18a43ba77ad070529ce58f5f3daadd1366c673b5 # Parent 2e738512336af85257cc040562f134b5cd6376e7# Parent 67c2b0fb9b19bdca75a3e83e94eed7f4e9158b18 Merge with 67c2b0fb9b19bdca75a3e83e94eed7f4e9158b18 diff -r 2e738512336a -r 18a43ba77ad0 .classpath --- a/.classpath Fri Oct 25 16:42:11 2013 +0200 +++ b/.classpath Wed Jan 15 18:36:27 2014 +0100 @@ -4,76 +4,31 @@ - - - - - - - - - - - - - - - - - - - + - + - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - + - + @@ -84,7 +39,7 @@ - + @@ -95,19 +50,19 @@ - + - + - + @@ -119,48 +74,48 @@ - + - + - + - + - + - + - + - + @@ -171,95 +126,59 @@ - + - + - + - + - + - + - + - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + @@ -269,10 +188,21 @@ - - - - - + + + + + + + + + + + + + + + + diff -r 2e738512336a -r 18a43ba77ad0 .hgignore diff -r 2e738512336a -r 18a43ba77ad0 .settings/org.eclipse.jdt.core.prefs --- a/.settings/org.eclipse.jdt.core.prefs Fri Oct 25 16:42:11 2013 +0200 +++ b/.settings/org.eclipse.jdt.core.prefs Wed Jan 15 18:36:27 2014 +0100 @@ -1,4 +1,10 @@ eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled +org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore +org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault +org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable +org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve @@ -6,6 +12,88 @@ org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=error +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=enabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=error +org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore +org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=error +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning +org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error +org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedImport=warning +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning org.eclipse.jdt.core.compiler.source=1.7 diff -r 2e738512336a -r 18a43ba77ad0 server/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/README.md Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,9 @@ +Dependencies + +- Icon user from echo-icon-theme (echo) (Open Icon Library - http://openiconlibrary.sourceforge.net/) +licence CC BY-SA - Creative Commons + +- cf pom.xml for dependencies + +Commandes maven: +mvn -DskipTests -Djava.awt.headless=true -Duser.timezone="UTC" clean jetty:run-war diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/admin-archetype/1.0.1-SNAPSHOT/_remote.repositories --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/admin-archetype/1.0.1-SNAPSHOT/_remote.repositories Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,4 @@ +#NOTE: This is an Aether internal implementation file, its format can be changed without prior notice. +#Mon Oct 14 16:54:20 CEST 2013 +admin-archetype-1.0.1-SNAPSHOT.jar>= +admin-archetype-1.0.1-SNAPSHOT.pom>= diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/admin-archetype/1.0.1-SNAPSHOT/admin-archetype-1.0.1-SNAPSHOT.jar Binary file server/lib/org/opencoweb/admin-archetype/1.0.1-SNAPSHOT/admin-archetype-1.0.1-SNAPSHOT.jar has changed diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/admin-archetype/1.0.1-SNAPSHOT/admin-archetype-1.0.1-SNAPSHOT.pom --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/admin-archetype/1.0.1-SNAPSHOT/admin-archetype-1.0.1-SNAPSHOT.pom Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,46 @@ + + + + + org.opencoweb + coweb-admin + 1.0.1-SNAPSHOT + + + 4.0.0 + org.opencoweb + admin-archetype + maven-archetype + OpenCoweb :: Java :: Admin :: Archetype + + + + + org.apache.maven.archetype + archetype-packaging + 2.0-alpha-5 + + + + + maven-archetype-plugin + 2.0-alpha-4 + true + + + + + ${basedir}/src/main/resources + false + + + ${basedir}/src/main/resources + + **/archetype-metadata.xml + + true + + + + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/admin-archetype/1.0.1-SNAPSHOT/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/admin-archetype/1.0.1-SNAPSHOT/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,24 @@ + + + org.opencoweb + admin-archetype + 1.0.1-SNAPSHOT + + + true + + 20131014145420 + + + jar + 1.0.1-SNAPSHOT + 20131014145420 + + + pom + 1.0.1-SNAPSHOT + 20131014145420 + + + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/admin-archetype/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/admin-archetype/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,11 @@ + + + org.opencoweb + admin-archetype + + + 1.0.1-SNAPSHOT + + 20131014145420 + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/admin-jar/1.0.1-SNAPSHOT/_remote.repositories --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/admin-jar/1.0.1-SNAPSHOT/_remote.repositories Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,4 @@ +#NOTE: This is an Aether internal implementation file, its format can be changed without prior notice. +#Mon Oct 14 16:54:21 CEST 2013 +admin-jar-1.0.1-SNAPSHOT.jar>= +admin-jar-1.0.1-SNAPSHOT.pom>= diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/admin-jar/1.0.1-SNAPSHOT/admin-jar-1.0.1-SNAPSHOT.jar Binary file server/lib/org/opencoweb/admin-jar/1.0.1-SNAPSHOT/admin-jar-1.0.1-SNAPSHOT.jar has changed diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/admin-jar/1.0.1-SNAPSHOT/admin-jar-1.0.1-SNAPSHOT.pom --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/admin-jar/1.0.1-SNAPSHOT/admin-jar-1.0.1-SNAPSHOT.pom Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,43 @@ + + + + + org.opencoweb + coweb-admin + 1.0.1-SNAPSHOT + + + 4.0.0 + admin-jar + jar + OpenCoweb :: Java :: Admin :: Jar + + + + javax + javaee-api + 6.0 + provided + + + javax.servlet + servlet-api + 2.5 + provided + + + org.apache.wink + wink-json4j + 1.1.2-incubating + jar + compile + + + org.opencoweb + coweb-server + ${project.version} + jar + provided + + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/admin-jar/1.0.1-SNAPSHOT/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/admin-jar/1.0.1-SNAPSHOT/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,24 @@ + + + org.opencoweb + admin-jar + 1.0.1-SNAPSHOT + + + true + + 20131014145421 + + + jar + 1.0.1-SNAPSHOT + 20131014145421 + + + pom + 1.0.1-SNAPSHOT + 20131014145421 + + + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/admin-jar/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/admin-jar/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,11 @@ + + + org.opencoweb + admin-jar + + + 1.0.1-SNAPSHOT + + 20131014145421 + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-admin/1.0.1-SNAPSHOT/_remote.repositories --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-admin/1.0.1-SNAPSHOT/_remote.repositories Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,3 @@ +#NOTE: This is an Aether internal implementation file, its format can be changed without prior notice. +#Mon Oct 14 16:54:20 CEST 2013 +coweb-admin-1.0.1-SNAPSHOT.pom>= diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-admin/1.0.1-SNAPSHOT/coweb-admin-1.0.1-SNAPSHOT.pom --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-admin/1.0.1-SNAPSHOT/coweb-admin-1.0.1-SNAPSHOT.pom Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,18 @@ + + + + org.opencoweb + coweb-java + 1.0.1-SNAPSHOT + + + 4.0.0 + coweb-admin + pom + OpenCoweb :: Java :: Admin + + + admin-archetype + admin-jar + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-admin/1.0.1-SNAPSHOT/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-admin/1.0.1-SNAPSHOT/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,19 @@ + + + org.opencoweb + coweb-admin + 1.0.1-SNAPSHOT + + + true + + 20131014145420 + + + pom + 1.0.1-SNAPSHOT + 20131014145420 + + + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-admin/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-admin/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,11 @@ + + + org.opencoweb + coweb-admin + + + 1.0.1-SNAPSHOT + + 20131014145420 + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-archetype/1.0.1-SNAPSHOT/_remote.repositories --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-archetype/1.0.1-SNAPSHOT/_remote.repositories Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,4 @@ +#NOTE: This is an Aether internal implementation file, its format can be changed without prior notice. +#Mon Oct 14 16:54:20 CEST 2013 +coweb-archetype-1.0.1-SNAPSHOT.jar>= +coweb-archetype-1.0.1-SNAPSHOT.pom>= diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-archetype/1.0.1-SNAPSHOT/coweb-archetype-1.0.1-SNAPSHOT.jar Binary file server/lib/org/opencoweb/coweb-archetype/1.0.1-SNAPSHOT/coweb-archetype-1.0.1-SNAPSHOT.jar has changed diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-archetype/1.0.1-SNAPSHOT/coweb-archetype-1.0.1-SNAPSHOT.pom --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-archetype/1.0.1-SNAPSHOT/coweb-archetype-1.0.1-SNAPSHOT.pom Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,45 @@ + + + + org.opencoweb + coweb-java + 1.0.1-SNAPSHOT + + + 4.0.0 + org.opencoweb + coweb-archetype + maven-archetype + OpenCoweb :: Java :: Archetype + + + + + org.apache.maven.archetype + archetype-packaging + 2.0-alpha-5 + + + + + maven-archetype-plugin + 2.0-alpha-4 + true + + + + + ${basedir}/src/main/resources + false + + + ${basedir}/src/main/resources + + **/archetype-metadata.xml + + true + + + + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-archetype/1.0.1-SNAPSHOT/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-archetype/1.0.1-SNAPSHOT/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,24 @@ + + + org.opencoweb + coweb-archetype + 1.0.1-SNAPSHOT + + + true + + 20131014145420 + + + jar + 1.0.1-SNAPSHOT + 20131014145420 + + + pom + 1.0.1-SNAPSHOT + 20131014145420 + + + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-archetype/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-archetype/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,11 @@ + + + org.opencoweb + coweb-archetype + + + 1.0.1-SNAPSHOT + + 20131014145420 + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-bots/1.0.1-SNAPSHOT/_remote.repositories --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-bots/1.0.1-SNAPSHOT/_remote.repositories Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,4 @@ +#NOTE: This is an Aether internal implementation file, its format can be changed without prior notice. +#Mon Oct 14 16:54:09 CEST 2013 +coweb-bots-1.0.1-SNAPSHOT.jar>= +coweb-bots-1.0.1-SNAPSHOT.pom>= diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-bots/1.0.1-SNAPSHOT/coweb-bots-1.0.1-SNAPSHOT.jar Binary file server/lib/org/opencoweb/coweb-bots/1.0.1-SNAPSHOT/coweb-bots-1.0.1-SNAPSHOT.jar has changed diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-bots/1.0.1-SNAPSHOT/coweb-bots-1.0.1-SNAPSHOT.pom --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-bots/1.0.1-SNAPSHOT/coweb-bots-1.0.1-SNAPSHOT.pom Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,14 @@ + + + + org.opencoweb + coweb-java + 1.0.1-SNAPSHOT + + + 4.0.0 + coweb-bots + org.opencoweb + jar + OpenCoweb :: Java :: Bots + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-bots/1.0.1-SNAPSHOT/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-bots/1.0.1-SNAPSHOT/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,24 @@ + + + org.opencoweb + coweb-bots + 1.0.1-SNAPSHOT + + + true + + 20131014145409 + + + jar + 1.0.1-SNAPSHOT + 20131014145409 + + + pom + 1.0.1-SNAPSHOT + 20131014145409 + + + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-bots/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-bots/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,11 @@ + + + org.opencoweb + coweb-bots + + + 1.0.1-SNAPSHOT + + 20131014145409 + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-build/1.0.1-SNAPSHOT/_remote.repositories --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-build/1.0.1-SNAPSHOT/_remote.repositories Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,4 @@ +#NOTE: This is an Aether internal implementation file, its format can be changed without prior notice. +#Mon Oct 14 16:54:22 CEST 2013 +coweb-build-1.0.1-SNAPSHOT.pom>= +coweb-build-1.0.1-SNAPSHOT.war>= diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-build/1.0.1-SNAPSHOT/coweb-build-1.0.1-SNAPSHOT.pom --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-build/1.0.1-SNAPSHOT/coweb-build-1.0.1-SNAPSHOT.pom Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,62 @@ + + + + org.opencoweb + coweb-java + 1.0.1-SNAPSHOT + + + 4.0.0 + coweb-build + OpenCoweb Build :: Applications + war + + + + + + org.apache.maven.plugins + maven-war-plugin + 2.1.1 + + + + org.opencoweb + coweb-javascript + war + + META-INF/** + WEB-INF/** + + lib + + + + + + + + + + org.opencoweb + coweb-bots + ${coweb-version} + + + org.opencoweb + coweb-operationengine + ${coweb-version} + + + org.opencoweb + coweb-server + ${coweb-version} + + + org.opencoweb + coweb-javascript + ${coweb-version} + war + + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-build/1.0.1-SNAPSHOT/coweb-build-1.0.1-SNAPSHOT.war Binary file server/lib/org/opencoweb/coweb-build/1.0.1-SNAPSHOT/coweb-build-1.0.1-SNAPSHOT.war has changed diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-build/1.0.1-SNAPSHOT/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-build/1.0.1-SNAPSHOT/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,24 @@ + + + org.opencoweb + coweb-build + 1.0.1-SNAPSHOT + + + true + + 20131014145422 + + + war + 1.0.1-SNAPSHOT + 20131014145422 + + + pom + 1.0.1-SNAPSHOT + 20131014145422 + + + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-build/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-build/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,11 @@ + + + org.opencoweb + coweb-build + + + 1.0.1-SNAPSHOT + + 20131014145422 + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-client/1.0.1-SNAPSHOT/_remote.repositories --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-client/1.0.1-SNAPSHOT/_remote.repositories Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,4 @@ +#NOTE: This is an Aether internal implementation file, its format can be changed without prior notice. +#Mon Oct 14 16:54:19 CEST 2013 +coweb-client-1.0.1-SNAPSHOT.jar>= +coweb-client-1.0.1-SNAPSHOT.pom>= diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-client/1.0.1-SNAPSHOT/coweb-client-1.0.1-SNAPSHOT.jar Binary file server/lib/org/opencoweb/coweb-client/1.0.1-SNAPSHOT/coweb-client-1.0.1-SNAPSHOT.jar has changed diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-client/1.0.1-SNAPSHOT/coweb-client-1.0.1-SNAPSHOT.pom --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-client/1.0.1-SNAPSHOT/coweb-client-1.0.1-SNAPSHOT.pom Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,22 @@ + + + + org.opencoweb + coweb-java + 1.0.1-SNAPSHOT + + + 4.0.0 + org.opencoweb + coweb-client + OpenCoweb :: Java :: Client + + + + org.cometd.java + cometd-java-client + ${cometd-version} + + + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-client/1.0.1-SNAPSHOT/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-client/1.0.1-SNAPSHOT/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,24 @@ + + + org.opencoweb + coweb-client + 1.0.1-SNAPSHOT + + + true + + 20131014145419 + + + jar + 1.0.1-SNAPSHOT + 20131014145419 + + + pom + 1.0.1-SNAPSHOT + 20131014145419 + + + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-client/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-client/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,11 @@ + + + org.opencoweb + coweb-client + + + 1.0.1-SNAPSHOT + + 20131014145419 + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-java/1.0.1-SNAPSHOT/_remote.repositories --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-java/1.0.1-SNAPSHOT/_remote.repositories Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,3 @@ +#NOTE: This is an Aether internal implementation file, its format can be changed without prior notice. +#Mon Oct 14 16:54:04 CEST 2013 +coweb-java-1.0.1-SNAPSHOT.pom>= diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-java/1.0.1-SNAPSHOT/coweb-java-1.0.1-SNAPSHOT.pom --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-java/1.0.1-SNAPSHOT/coweb-java-1.0.1-SNAPSHOT.pom Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,139 @@ + + + + 4.0.0 + org.opencoweb + coweb-java + pom + + OpenCoweb + Open Cooperative Web Framework + 1.0.1-SNAPSHOT + http://opencoweb.org + 2011 + + The Dojo Foundation + http://dojofoundation.org + + + + + The New BSD License + http://www.opensource.org/licenses/bsd-license.html + + + The Academic Free License, v. 2.1 + http://en.wikipedia.org/wiki/Academic_Free_License + + + + + + parente + Peter Parente + pparent@us.ibm.com + IBM Corporation + + + bpburns + Brian Burns + bburns@us.ibm.com + IBM Corporation + + + vinomaster + Dan Gisolfi + gisolfi@us.ibm.com + IBM Corporation + + + + + scm:git:git@github.com:opencoweb/coweb.git + scm:git:git@github.com:opencoweb/coweb.git + git@github.com:opencoweb/coweb.git + + + + UTF-8 + 2.7.0 + 1.0.1-SNAPSHOT + + + + coweb-operationengine + coweb-bots + coweb-server + coweb-javascript + coweb-client + coweb-archetype + coweb-admin + coweb-build + + + + install + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.7 + + ${project.name} ${project.version} Java Server API + + + + aggregate + + aggregate + + site + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.6 + 1.6 + + + + + + + + release-sign-artifacts + + + performRelease + true + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.1 + + + sign-artifacts + verify + + sign + + + + + + + + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-java/1.0.1-SNAPSHOT/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-java/1.0.1-SNAPSHOT/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,19 @@ + + + org.opencoweb + coweb-java + 1.0.1-SNAPSHOT + + + true + + 20131014145404 + + + pom + 1.0.1-SNAPSHOT + 20131014145404 + + + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-java/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-java/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,11 @@ + + + org.opencoweb + coweb-java + + + 1.0.1-SNAPSHOT + + 20131014145404 + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-javascript/1.0.1-SNAPSHOT/_remote.repositories --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-javascript/1.0.1-SNAPSHOT/_remote.repositories Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,4 @@ +#NOTE: This is an Aether internal implementation file, its format can be changed without prior notice. +#Mon Oct 14 16:54:19 CEST 2013 +coweb-javascript-1.0.1-SNAPSHOT.pom>= +coweb-javascript-1.0.1-SNAPSHOT.war>= diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-javascript/1.0.1-SNAPSHOT/coweb-javascript-1.0.1-SNAPSHOT.pom --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-javascript/1.0.1-SNAPSHOT/coweb-javascript-1.0.1-SNAPSHOT.pom Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,110 @@ + + + + org.opencoweb + coweb-java + 1.0.1-SNAPSHOT + + + 4.0.0 + org.opencoweb + coweb-javascript + OpenCoweb :: Java :: JavaScript + war + + + http://requirejs.org/docs/release/1.0.0/minified/i18n.js + ${project.build.directory}/${project.artifactId}-${project.version}/coweb/jsoe + src/main/webapp/coweb/jsoe + + + + + + org.apache.maven.plugins + maven-war-plugin + 2.2 + + coweb/jsoe/ + + + + org.apache.maven.plugins + maven-dependency-plugin + 2.4 + + + unpack + compile + unpack + + + + org.cometd.javascript + cometd-javascript-common + ${cometd.version} + war + false + ${project.build.directory}/tmp + **/cometd.js,**/cometd/AckExtension.js + + + + + + + + + + maven-antrun-plugin + + + prepare-package + + + + + + + + + + + + + + + + + + + + + + + + + + + + + run + + + + + + + + + org.cometd.javascript + cometd-javascript-common + ${cometd-version} + war + provided + + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-javascript/1.0.1-SNAPSHOT/coweb-javascript-1.0.1-SNAPSHOT.war Binary file server/lib/org/opencoweb/coweb-javascript/1.0.1-SNAPSHOT/coweb-javascript-1.0.1-SNAPSHOT.war has changed diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-javascript/1.0.1-SNAPSHOT/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-javascript/1.0.1-SNAPSHOT/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,24 @@ + + + org.opencoweb + coweb-javascript + 1.0.1-SNAPSHOT + + + true + + 20131014145419 + + + war + 1.0.1-SNAPSHOT + 20131014145419 + + + pom + 1.0.1-SNAPSHOT + 20131014145419 + + + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-javascript/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-javascript/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,11 @@ + + + org.opencoweb + coweb-javascript + + + 1.0.1-SNAPSHOT + + 20131014145419 + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-operationengine/1.0.1-SNAPSHOT/_remote.repositories --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-operationengine/1.0.1-SNAPSHOT/_remote.repositories Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,4 @@ +#NOTE: This is an Aether internal implementation file, its format can be changed without prior notice. +#Mon Oct 14 16:54:09 CEST 2013 +coweb-operationengine-1.0.1-SNAPSHOT.jar>= +coweb-operationengine-1.0.1-SNAPSHOT.pom>= diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-operationengine/1.0.1-SNAPSHOT/coweb-operationengine-1.0.1-SNAPSHOT.jar Binary file server/lib/org/opencoweb/coweb-operationengine/1.0.1-SNAPSHOT/coweb-operationengine-1.0.1-SNAPSHOT.jar has changed diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-operationengine/1.0.1-SNAPSHOT/coweb-operationengine-1.0.1-SNAPSHOT.pom --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-operationengine/1.0.1-SNAPSHOT/coweb-operationengine-1.0.1-SNAPSHOT.pom Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,14 @@ + + + + org.opencoweb + coweb-java + 1.0.1-SNAPSHOT + + + 4.0.0 + org.opencoweb + coweb-operationengine + OpenCoweb :: Java :: OperationEngine + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-operationengine/1.0.1-SNAPSHOT/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-operationengine/1.0.1-SNAPSHOT/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,24 @@ + + + org.opencoweb + coweb-operationengine + 1.0.1-SNAPSHOT + + + true + + 20131014145409 + + + jar + 1.0.1-SNAPSHOT + 20131014145409 + + + pom + 1.0.1-SNAPSHOT + 20131014145409 + + + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-operationengine/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-operationengine/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,11 @@ + + + org.opencoweb + coweb-operationengine + + + 1.0.1-SNAPSHOT + + 20131014145409 + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-server/1.0.1-SNAPSHOT/_remote.repositories --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-server/1.0.1-SNAPSHOT/_remote.repositories Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,4 @@ +#NOTE: This is an Aether internal implementation file, its format can be changed without prior notice. +#Mon Oct 14 16:54:10 CEST 2013 +coweb-server-1.0.1-SNAPSHOT.pom>= +coweb-server-1.0.1-SNAPSHOT.jar>= diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-server/1.0.1-SNAPSHOT/coweb-server-1.0.1-SNAPSHOT.jar Binary file server/lib/org/opencoweb/coweb-server/1.0.1-SNAPSHOT/coweb-server-1.0.1-SNAPSHOT.jar has changed diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-server/1.0.1-SNAPSHOT/coweb-server-1.0.1-SNAPSHOT.pom --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-server/1.0.1-SNAPSHOT/coweb-server-1.0.1-SNAPSHOT.pom Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,53 @@ + + + + org.opencoweb + coweb-java + 1.0.1-SNAPSHOT + + + 4.0.0 + org.opencoweb + coweb-server + OpenCoweb :: Java :: Server + + + + org.opencoweb + coweb-bots + ${project.version} + + + org.opencoweb + coweb-operationengine + ${project.version} + + + org.cometd.java + cometd-java-server + ${cometd-version} + + + org.cometd.java + bayeux-api + ${cometd-version} + + + org.cometd.java + cometd-java-common + ${cometd-version} + + + org.cometd.java + cometd-websocket-jetty + ${cometd-version} + + + javax.servlet + servlet-api + 2.5 + provided + + + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-server/1.0.1-SNAPSHOT/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-server/1.0.1-SNAPSHOT/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,24 @@ + + + org.opencoweb + coweb-server + 1.0.1-SNAPSHOT + + + true + + 20131014145410 + + + jar + 1.0.1-SNAPSHOT + 20131014145410 + + + pom + 1.0.1-SNAPSHOT + 20131014145410 + + + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/coweb-server/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/coweb-server/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,11 @@ + + + org.opencoweb + coweb-server + + + 1.0.1-SNAPSHOT + + 20131014145410 + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/opencoweb/maven-metadata-local.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/opencoweb/maven-metadata-local.xml Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,15 @@ + + + + + OpenCoweb :: Java :: Archetype + coweb-archetype + coweb-archetype + + + OpenCoweb :: Java :: Admin :: Archetype + admin-archetype + admin-archetype + + + diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/thymeleaf/extras/thymeleaf-joda-dialect/0.0.3/thymeleaf-joda-dialect-0.0.3.jar Binary file server/lib/org/thymeleaf/extras/thymeleaf-joda-dialect/0.0.3/thymeleaf-joda-dialect-0.0.3.jar has changed diff -r 2e738512336a -r 18a43ba77ad0 server/lib/org/thymeleaf/extras/thymeleaf-joda-dialect/0.0.3/thymeleaf-joda-dialect-0.0.3.pom --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/lib/org/thymeleaf/extras/thymeleaf-joda-dialect/0.0.3/thymeleaf-joda-dialect-0.0.3.pom Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,145 @@ + + 4.0.0 + org.thymeleaf.extras + thymeleaf-joda-dialect + 0.0.3 + 2013 + + + Tom-Steve Watzke + ts.watzke@pitcom.de + + Project creator and Lead developer + + + + Dieter Hubau + dhubau@gmail.com + + Developer + + + + Thymeleaf dialect for formatting Joda Time objects + + + 1.7 + 3.2.4.RELEASE + 3.2.4.RELEASE + 2.1.1.RELEASE + + + + + org.springframework + spring-beans + ${org.springframework-version} + + + org.springframework + spring-webmvc + ${org.springframework-version} + + + + + org.thymeleaf + thymeleaf + ${org.thymeleaf-version} + jar + compile + + + org.thymeleaf + thymeleaf-spring3 + ${org.thymeleaf-version} + jar + compile + + + + joda-time + joda-time + 2.1 + jar + compile + + + + javax.servlet + servlet-api + 2.5 + provided + + + + org.springframework + spring-test + ${org.springframework-version} + test + + + junit + junit + 4.8.1 + test + + + + + + + org.apache.tomcat.maven + tomcat7-maven-plugin + 2.0 + + + deploy + pre-integration-test + + deploy + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + ${java-version} + ${java-version} + -Xlint:all + true + true + false + + + + + + + + + spring-snapshot + Spring Maven SNAPSHOT Repository + http://repo.springsource.org/libs-snapshot + + + + SpringSource Enterprise Bundle Repository - SpringSource Bundle Releases + http://repository.springsource.com/maven/bundles/release + + + + SpringSource Enterprise Bundle Repository - External Bundle Releases + http://repository.springsource.com/maven/bundles/external + + + java.net + http://download.java.net/maven/2/ + + + diff -r 2e738512336a -r 18a43ba77ad0 server/pom.xml --- a/server/pom.xml Fri Oct 25 16:42:11 2013 +0200 +++ b/server/pom.xml Wed Jan 15 18:36:27 2014 +0100 @@ -4,23 +4,42 @@ 4.0.0 org.iri_research.renkan renkan - 0.7.2 + 0.7.3 war - 2.14 - 1.0 + 2.16 + 1.0.1-SNAPSHOT 1.0 - 1.17.1 - 3.2.1.RELEASE - 3.1.3.RELEASE - 8.1.10.v20130312 - 4.10 - 2.0.16 - 2.0.0 - 2.5.1 - 2.1.4 - 2.1 + 2.3.1 + 3.2.4.RELEASE + 1.3.1.RELEASE + 3.1.4.RELEASE + 1.6.1.RELEASE + 1.4.1.RELEASE + 8.1.13.v20130916 + 8.1.13.v20130916 + 4.11 + 2.1.1.RELEASE + 2.1.0.RELEASE + 0.0.3 + 2.7.0 + 2.2.3 + 2.3 + 2.11.3 + 2.0 + 1.2 + 1 + 3.0.1 + 1.2 + 1.0.2 + 1.1.0.Final + 5.0.1.Final + 1.7.5 + 1.9.19 + 1.8 + 2.2.3 + 3.1.3 UTF-8 @@ -30,17 +49,20 @@ org.apache.maven.plugins maven-compiler-plugin - 3.0 + 3.1 1.7 1.7 + + -Xlint + org.mortbay.jetty jetty-maven-plugin - ${jetty-version} + ${jetty-plugin-version} 10 @@ -53,7 +75,7 @@ maven-war-plugin 2.3 - + true true @@ -125,10 +147,24 @@ maven-surefire-plugin ${surefire-version} + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + lib + lib + + true + ignore + + file://${project.basedir}/lib + + spring-maven-release Spring Maven Release Repository http://maven.springframework.org/release @@ -142,24 +178,39 @@ spring-release Spring Maven SNAPSHOT Repository http://repo.springsource.org/release - + javax.inject javax.inject - 1 + ${javax-inject-version} javax.servlet javax.servlet-api - 3.0.1 + ${javax-servlet-api-version} + + + javax.ws.rs + javax.ws.rs-api + ${jaxrs-api-version} + + + javax.annotation + javax.annotation-api + ${javax-annotation-version} + + + org.cometd.java + bayeux-api + ${cometd-version} org.cometd.java cometd-java-common ${cometd-version} - + org.cometd.java cometd-java-annotations @@ -169,7 +220,7 @@ org.cometd.java cometd-websocket-jetty ${cometd-version} - + org.opencoweb coweb-bots @@ -193,57 +244,35 @@ war - com.sun.jersey - jersey-server - ${jersey-version} + org.glassfish.jersey.core + jersey-server + ${jersey-version} + - com.sun.jersey - jersey-json + org.glassfish.jersey.ext + jersey-spring3 ${jersey-version} - com.sun.jersey.contribs - jersey-spring + org.glassfish.jersey.test-framework.providers + jersey-test-framework-provider-grizzly2 ${jersey-version} - - - org.springframework - spring-context - - - org.springframework - spring-beans - - - org.springframework - spring-core - - - org.springframework - spring-web - - - org.springframework - spring-aop - - + test - - com.sun.jersey.jersey-test-framework - jersey-test-framework-grizzly2 - ${jersey-version} - test - org.mongodb mongo-java-driver - 2.10.1 + ${mongo-driver-version} org.slf4j slf4j-log4j12 - 1.7.2 + ${slf4j-log4j12-version} org.springframework @@ -259,13 +288,13 @@ org.springframework spring-web ${spring-version} - + org.springframework spring-test ${spring-version} test - + org.springframework spring-webmvc @@ -274,33 +303,33 @@ org.springframework.data spring-data-commons - 1.5.0.RELEASE + ${spring-data-commons-version} org.springframework.data spring-data-jpa - 1.3.0.RELEASE + ${spring-data-jpa-version} org.springframework.data spring-data-mongodb - 1.2.0.RELEASE + ${spring-data-mongodb-version} javax.persistence persistence-api - 1.0.2 + ${javax-persistence-api-version} - - junit - junit + + junit + junit ${junit-version} - test + test javax.servlet jstl - 1.2 + ${javax-servlet-jstl-version} runtime @@ -319,9 +348,29 @@ ${thymeleaf-springsecurity-version} + org.thymeleaf.extras + thymeleaf-joda-dialect + ${thymeleaf-joda-dialect-version} + + net.sourceforge.nekohtml nekohtml - 1.9.16 + ${nekohtml-version} + + + com.fasterxml.jackson.core + jackson-core + ${jackson-version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson-version} + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson-version} com.fasterxml.jackson.jaxrs @@ -329,38 +378,18 @@ ${jackson-version} + com.fasterxml.jackson.datatype + jackson-datatype-joda + ${jackson-version} + + commons-codec commons-codec - 1.7 - - - org.eclipse.jetty - jetty-server - ${jetty-version} - - - org.eclipse.jetty - jetty-client - ${jetty-version} + ${commons-codec-version} - org.eclipse.jetty - jetty-websocket - ${jetty-version} - - - org.eclipse.jetty - jetty-jmx - ${jetty-version} - - - org.eclipse.jetty - jetty-util - ${jetty-version} - - - org.eclipse.jetty - jetty-servlets + org.eclipse.jetty.aggregate + jetty-all ${jetty-version} @@ -391,7 +420,7 @@ de.undercouch bson4jackson - 2.1.1 + ${bson4jackson-version} joda-time @@ -401,21 +430,26 @@ javax.validation validation-api - 1.1.0.CR2 + ${javax-validation-api-version} org.hibernate hibernate-validator - 4.2.0.Final + ${hibernate-validator-version} com.fasterxml.uuid java-uuid-generator - 3.1.3 + ${fasterxml-java-uuid-generator-version} + + + org.apache.commons + commons-collections4 + 4.0 - IRI - http://www.iri.centrepompidou.fr + IRI + http://www.iri.centrepompidou.fr diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/Constants.java --- a/server/src/main/java/org/iri_research/renkan/Constants.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/Constants.java Wed Jan 15 18:36:27 2014 +0100 @@ -10,70 +10,94 @@ public class Constants { - - static { - - } - - public final static List VERSION = Collections.unmodifiableList(new ArrayList() { - private static final long serialVersionUID = -6935554100028328149L; - { - add("0"); - add("7"); - add("2"); - add("final"); - add("0"); - } - }); - - public static String getVersion() { - - String[] version_array = VERSION.toArray(new String[VERSION.size()]); - - String version = String.format("%s.%s",version_array[0], version_array[1]); - if(version_array[2] != null && !version_array[2].isEmpty() && Integer.parseInt(version_array[2]) > 0 ) { - version = String.format("%s.%s", version, version_array[2]); - } - if (version_array[3] == "alpha" && version_array[4] == "0") { - version = String.format("%s pre-alpha",version); - } - else if(version_array[3] != "final") { - version = String.format("%s %s %s", version, version_array[3], version_array[4]); - } - return version; + static { + + } + + public final static List VERSION = Collections + .unmodifiableList(new ArrayList() { + private static final long serialVersionUID = -6935554100028328149L; + { + add("0"); + add("7"); + add("3"); + add("alpha"); + add("1"); + } + }); + + public static String getVersion() { + + String[] version_array = VERSION.toArray(new String[VERSION.size()]); + + String version = String.format("%s.%s", version_array[0], + version_array[1]); + if (version_array[2] != null && !version_array[2].isEmpty() + && Integer.parseInt(version_array[2]) > 0) { + version = String.format("%s.%s", version, version_array[2]); + } + if (version_array[3] == "alpha" && version_array[4] == "0") { + version = String.format("%s pre-alpha", version); + } else if (version_array[3] != "final") { + version = String.format("%s %s %s", version, version_array[3], + version_array[4]); + } + return version; + + } + + public final static String KEYHEX = "f2338d2299ac28ef64f82956fde37337b87a2b9e8fc03e28fa0768cac37d838113c7d0fc78c60fce1e23b1b3e03ac7db4676b3189c267f26baaab10f72544441"; + public final static int SALT_LENGTH = 24; + public final static int PAGINATION_SIZE = 10; + public final static String PROPERTIES_SERVLET_CONTEXT_NAME = "renkan.properties"; + public final static String PROPERTIES_CLASSPATH_NAME = "renkan_run.properties"; + public final static String ANONYMOUS_USER_BASE_NAME = "Anonymous"; - } - - public final static String KEYHEX = "f2338d2299ac28ef64f82956fde37337b87a2b9e8fc03e28fa0768cac37d838113c7d0fc78c60fce1e23b1b3e03ac7db4676b3189c267f26baaab10f72544441"; - public final static int SALT_LENGTH = 24; - public final static int PAGINATION_SIZE = 10; - public final static String PROPERTIES_SERVLET_CONTEXT_NAME = "renkan.properties"; - public final static String PROPERTIES_CLASSPATH_NAME = "renkan_run.properties"; - - private final static EthernetAddress ETHERNET_ADRESS = EthernetAddress.fromInterface(); - public final static NoArgGenerator UUID_GENERATOR = Generators.timeBasedGenerator(ETHERNET_ADRESS); + private final static EthernetAddress ETHERNET_ADRESS = EthernetAddress + .fromInterface(); + public final static NoArgGenerator UUID_GENERATOR = Generators + .timeBasedGenerator(ETHERNET_ADRESS); + + public enum EditMode { + READ_ONLY(1), EDITION(2); + + private int value; + + private final static EditMode[] editModeValues = EditMode.values(); + + private EditMode(int i) { + this.value = i; + } - public enum EditMode { - READ_ONLY(1), - EDITION(2); - - private int value; - - private final static EditMode[] editModeValues = EditMode.values(); - - private EditMode(int i) { - this.value = i; - } - - public static EditMode fromInt(int val) { - for(int i=0; i < editModeValues.length; i++) { - if(editModeValues[i].value == val) - { - return editModeValues[i]; - } - } - return null; - } - } + public static EditMode fromInt(int val) { + for (int i = 0; i < editModeValues.length; i++) { + if (editModeValues[i].value == val) { + return editModeValues[i]; + } + } + return null; + } + } + + public final static String ROLE_USER = "ROLE_USER"; + + public final static List USER_ROLES_SELECT = Collections + .unmodifiableList(new ArrayList() { + private static final long serialVersionUID = -3041530185134732199L; + { + add("ROLE_ADMIN"); + add("ROLE_SPACES_ADMIN"); + add("ROLE_GROUPS_ADMIN"); + } + }); + + public final static List USER_ROLES_ALL = Collections + .unmodifiableList(new ArrayList() { + private static final long serialVersionUID = -3041530185134732199L; + { + add(ROLE_USER); + addAll(USER_ROLES_SELECT); + } + }); } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/RenkanException.java --- a/server/src/main/java/org/iri_research/renkan/RenkanException.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/RenkanException.java Wed Jan 15 18:36:27 2014 +0100 @@ -2,24 +2,24 @@ public class RenkanException extends Exception { - /** + /** * */ - private static final long serialVersionUID = -6952770322990047437L; + private static final long serialVersionUID = -6952770322990047437L; - public RenkanException() { - } + public RenkanException() { + } - public RenkanException(String message) { - super(message); - } + public RenkanException(String message) { + super(message); + } - public RenkanException(Throwable exc) { - super(exc); - } + public RenkanException(Throwable exc) { + super(exc); + } - public RenkanException(String message, Throwable exc) { - super(message, exc); - } + public RenkanException(String message, Throwable exc) { + super(message, exc); + } } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/RenkanProperties.java --- a/server/src/main/java/org/iri_research/renkan/RenkanProperties.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/RenkanProperties.java Wed Jan 15 18:36:27 2014 +0100 @@ -11,35 +11,37 @@ @Named public class RenkanProperties { - @Resource(name="renkanProperties") - private Properties properties; - - private final Logger logger = LoggerFactory.getLogger(RenkanProperties.class); - + @Resource(name = "renkanProperties") + private Properties properties; + + private final Logger logger = LoggerFactory + .getLogger(RenkanProperties.class); + private static volatile RenkanProperties instance = null; - - private RenkanProperties() - { - this.logger.debug("Building RenkanProperties"); + + private RenkanProperties() { + this.logger.debug("Building RenkanProperties"); } - + public static RenkanProperties getInstance() { - if (instance == null) { - synchronized (RenkanProperties.class) { - if(instance == null) { - instance = new RenkanProperties(); - } - } - } - return instance; + if (instance == null) { + synchronized (RenkanProperties.class) { + if (instance == null) { + instance = new RenkanProperties(); + } + } + } + return instance; } - - public int getPaginationSize() { - return Integer.parseInt(properties.getProperty("renkan.pagination.size", Integer.toString(Constants.PAGINATION_SIZE))); - } - public String getProperty(String name, String defaultVal) { - return properties.getProperty(name, defaultVal); - } - + public int getPaginationSize() { + return Integer.parseInt(properties.getProperty( + "renkan.pagination.size", + Integer.toString(Constants.PAGINATION_SIZE))); + } + + public String getProperty(String name, String defaultVal) { + return properties.getProperty(name, defaultVal); + } + } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/RenkanRuntimeException.java --- a/server/src/main/java/org/iri_research/renkan/RenkanRuntimeException.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/RenkanRuntimeException.java Wed Jan 15 18:36:27 2014 +0100 @@ -2,25 +2,24 @@ public class RenkanRuntimeException extends RuntimeException { - - /** + /** * */ - private static final long serialVersionUID = 736470650035855769L; + private static final long serialVersionUID = 736470650035855769L; - public RenkanRuntimeException() { - } + public RenkanRuntimeException() { + } - public RenkanRuntimeException(String message) { - super(message); - } + public RenkanRuntimeException(String message) { + super(message); + } - public RenkanRuntimeException(Throwable exc) { - super(exc); - } + public RenkanRuntimeException(Throwable exc) { + super(exc); + } - public RenkanRuntimeException(String message, Throwable exc) { - super(message, exc); - } + public RenkanRuntimeException(String message, Throwable exc) { + super(message, exc); + } } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/controller/AdminController.java --- a/server/src/main/java/org/iri_research/renkan/controller/AdminController.java Fri Oct 25 16:42:11 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,195 +0,0 @@ -package org.iri_research.renkan.controller; - -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.Arrays; -import java.util.Map; - -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; - -import org.apache.commons.codec.binary.Hex; -import org.iri_research.renkan.Constants; -import org.iri_research.renkan.RenkanException; -import org.iri_research.renkan.forms.SpaceForm; -import org.iri_research.renkan.forms.SpaceFormValidator; -import org.iri_research.renkan.models.Space; -import org.iri_research.renkan.repositories.ProjectsRepository; -import org.iri_research.renkan.repositories.SpacesRepository; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort.Direction; -import org.springframework.data.web.PageableDefaults; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.validation.BindingResult; -import org.springframework.web.bind.WebDataBinder; -import org.springframework.web.bind.annotation.InitBinder; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.client.HttpClientErrorException; - -@Controller -@RequestMapping("/admin") -public class AdminController { - - private final Logger logger = LoggerFactory.getLogger(AdminController.class); - - @Autowired - private SpacesRepository spacesRepository; - @Autowired - private ProjectsRepository projectsRepository; - - @InitBinder(value={"space"}) - protected void initBinder(WebDataBinder binder) { - binder.setValidator(new SpaceFormValidator()); - } - - @RequestMapping(value="", method = RequestMethod.GET, produces={"text/html;charset=UTF-8"}) - public String adminIndex() { - - return "admin/adminIndex"; - } - - @RequestMapping(value="/spaces", method = RequestMethod.GET, produces={"text/html;charset=UTF-8"}) - public String spacesList( - Model model, - @PageableDefaults(sort={"created"}, sortDir=Direction.DESC, pageNumber=0, value=Constants.PAGINATION_SIZE) Pageable p, - HttpServletRequest request) { - - Page page = this.spacesRepository.findAll(p); - - model.addAttribute("page", page); - model.addAttribute("baseUrl", Utils.buildBaseUrl(request)); - model.addAttribute("projectsCount", this.projectsRepository.getCountBySpace()); - - return "admin/spacesList"; - } - - @RequestMapping(value="/spaces/edit/", method = RequestMethod.GET, produces={"text/html;charset=UTF-8"}) - public String editSpace(Model model) { - return editSpace(model, null); - } - - @RequestMapping(value="/spaces/edit/{spaceId}", method = RequestMethod.GET, produces={"text/html;charset=UTF-8"}) - public String editSpace(Model model, @PathVariable(value="spaceId") String spaceId) { - - SpaceForm spaceForm = null; - - if(spaceId == null || spaceId.length() == 0 || "_".equals(spaceId)) { - spaceForm = new SpaceForm(); - } - else { - Space space = this.spacesRepository.findOne(spaceId); - if(space == null) { - throw new HttpClientErrorException(HttpStatus.NOT_FOUND, "space " + spaceId + " not found"); - } - spaceForm = new SpaceForm(space); - } - - model.addAttribute("space", spaceForm); - - return "admin/spaceEdit"; - } - - - @RequestMapping(value="/spaces/save", method = RequestMethod.POST) - public String saveSpace(Model model, @ModelAttribute("space") @Valid SpaceForm spaceForm, BindingResult bindingResult) { - - logger.debug("space title " + spaceForm.getTitle()); - logger.debug("space description " + spaceForm.getDescription()); - - if(bindingResult.hasErrors()) { - return "admin/spaceEdit"; - } - - spaceForm.setSpacesRepository(spacesRepository); - - try { - spaceForm.save(); - } catch (RenkanException e) { - throw new HttpClientErrorException(HttpStatus.NOT_FOUND, "space " + spaceForm.getId() + " not found"); - } - - return "redirect:/admin/spaces"; - } - - //@RequestMapping(value="/spaces/confirmdelete/{spaceId}", method = RequestMethod.GET) - //public String askDeleteSpace(Model model, @PathVariable(value="spaceId") String spaceId) { - - - //} - - @RequestMapping(value="/spaces/delete/{spaceId}") - public String deleteSpace( - HttpServletRequest request, - Model model, - @PathVariable(value="spaceId") String spaceId, - @RequestParam(value="key", required=false) String key, - @RequestParam(value="salt", required=false) String salt) throws NoSuchAlgorithmException, RenkanException - { - - if(spaceId == null || spaceId.length() == 0) { - throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, "Null or empty space id"); - } - - RequestMethod method = RequestMethod.valueOf(request.getMethod()); - - Map nbProj = this.projectsRepository.getCountBySpace(Arrays.asList(spaceId)); - if(nbProj.containsKey(spaceId) && nbProj.get(spaceId).intValue()>0) { - throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, "This space have projects"); - } - - if(RequestMethod.GET.equals(method)) { - - Space space = this.spacesRepository.findOne(spaceId); - - if(space == null) { - throw new HttpClientErrorException(HttpStatus.NOT_FOUND, "space " + spaceId + " not found"); - } - - SecureRandom rand = SecureRandom.getInstance("SHA1PRNG"); - rand.setSeed(System.currentTimeMillis()); - byte[] rawSalt = new byte[50]; - rand.nextBytes(rawSalt); - String newSalt = Hex.encodeHexString(rawSalt); - - - model.addAttribute("spaceObj", space); - model.addAttribute("salt", newSalt); - model.addAttribute("key", space.getKey(newSalt)); - - return "admin/spaceDeleteConfirm"; - } - else if (RequestMethod.POST.equals(method) && key != null && !key.isEmpty() && salt != null && !salt.isEmpty()) { - - if(spaceId != null && spaceId.length() > 0) { - - Space space = this.spacesRepository.findOne(spaceId); - if(space != null) { - if(space.checkKey(key, salt)) { - this.spacesRepository.delete(spaceId); - } - else { - throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, "Key not ckecked"); - } - } - - } - return "redirect:/admin/spaces"; - - } - else { - throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, "Bad request method or parameters"); - } - - } - -} diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/controller/AuthController.java --- a/server/src/main/java/org/iri_research/renkan/controller/AuthController.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/controller/AuthController.java Wed Jan 15 18:36:27 2014 +0100 @@ -10,21 +10,20 @@ @Controller @RequestMapping("/auth") public class AuthController { - - @SuppressWarnings("unused") - private final Logger logger = LoggerFactory.getLogger(AuthController.class); - - @RequestMapping(value="/login", method = RequestMethod.GET, produces={"text/html;charset=UTF-8"}) - public String login() { - return "auth/login"; - } + + @SuppressWarnings("unused") + private final Logger logger = LoggerFactory.getLogger(AuthController.class); + + @RequestMapping(value = "/login", method = RequestMethod.GET, produces = { "text/html;charset=UTF-8" }) + public String login() { + return "auth/login"; + } - @RequestMapping(value="/loginfailed", method = RequestMethod.GET, produces={"text/html;charset=UTF-8"}) - public String loginFailed(Model model) { - - model.addAttribute("login_error", true); - return "auth/login"; - } + @RequestMapping(value = "/loginfailed", method = RequestMethod.GET, produces = { "text/html;charset=UTF-8" }) + public String loginFailed(Model model) { - + model.addAttribute("login_error", true); + return "auth/login"; + } + } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/controller/RenkanController.java --- a/server/src/main/java/org/iri_research/renkan/controller/RenkanController.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/controller/RenkanController.java Wed Jan 15 18:36:27 2014 +0100 @@ -27,104 +27,116 @@ import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.servlet.ModelAndView; - @Controller @RequestMapping("/p") public class RenkanController { - private final Logger logger = LoggerFactory.getLogger(RenkanController.class); - - @Autowired - private ProjectsRepository projectsRepository; - - @Autowired - private SpacesRepository spacesRepository; - - private void checkCowebkey(String cowebkey, Project project, Constants.EditMode editMode) { - if(cowebkey == null || cowebkey.isEmpty()) { - throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, "Cowebkey missing"); - } - try { - if(!project.checkKey(cowebkey, editMode)) { - throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, "Bad cowebkey"); - } - } catch (RenkanException e) { - throw new HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage()); - } - } - - @RequestMapping(value="/copy", method = RequestMethod.POST, produces={"application/json;charset=UTF-8"}) - public @ResponseBody Project copyProject(@RequestParam(value="project_id") String projectId ) { - - if(projectId == null || projectId.length() == 0) { - throw new IllegalArgumentException("RenkanContoller.renkanProject.copyProject: Project id is null or empty."); - } - Project project = this.projectsRepository.findOne(projectId); - if(project == null) { - throw new HttpClientErrorException(HttpStatus.NOT_FOUND, "Project " + projectId + " not found for copyProject."); - } + private final Logger logger = LoggerFactory + .getLogger(RenkanController.class); + + @Autowired + private ProjectsRepository projectsRepository; + + @Autowired + private SpacesRepository spacesRepository; + + private void checkCowebkey(String cowebkey, Project project, + Constants.EditMode editMode) { + if (cowebkey == null || cowebkey.isEmpty()) { + throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, + "Cowebkey missing"); + } + try { + if (!project.checkKey(cowebkey, editMode)) { + throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, + "Bad cowebkey"); + } + } catch (RenkanException e) { + throw new HttpServerErrorException( + HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage()); + } + } - Project newProject = this.projectsRepository.copy(project, project.getTitle() + " (copy)"); - - return newProject; - } + @RequestMapping(value = "/copy", method = RequestMethod.POST, produces = { "application/json;charset=UTF-8" }) + public @ResponseBody + Project copyProject(@RequestParam(value = "project_id") String projectId) { + + if (projectId == null || projectId.length() == 0) { + throw new IllegalArgumentException( + "RenkanContoller.renkanProject.copyProject: Project id is null or empty."); + } + Project project = this.projectsRepository.findOne(projectId); + if (project == null) { + throw new HttpClientErrorException(HttpStatus.NOT_FOUND, "Project " + + projectId + " not found for copyProject."); + } - - @RequestMapping(value="/{project_id}", method = RequestMethod.GET, produces={"text/html;charset=UTF-8", "!image/*"}) - public ModelAndView renkanProject( - @PathVariable(value="project_id") String project_id, - @RequestHeader(value="Accept") String accept_header, - @RequestParam(value="cowebkey") String cowebkey - ) throws HttpMediaTypeNotSupportedException - { + Project newProject = this.projectsRepository.copy(project, + project.getTitle() + " (copy)"); + + return newProject; + } + + @RequestMapping(value = "/{project_id}", method = RequestMethod.GET, produces = { + "text/html;charset=UTF-8", "!image/*" }) + public ModelAndView renkanProject( + @PathVariable(value = "project_id") String project_id, + @RequestHeader(value = "Accept") String accept_header, + @RequestParam(value = "cowebkey") String cowebkey) + throws HttpMediaTypeNotSupportedException { - this.logger.debug("renkanProject : " + project_id + " Accept : " + accept_header!=null?accept_header:"" + ", cowebkey: "+ cowebkey!=null?cowebkey:""); - - - if(project_id == null || project_id.length() == 0) { - throw new IllegalArgumentException("RenkanContoller.renkanProject: Project id is null or empty."); - } - - Project project = this.projectsRepository.findOne(project_id); - - if(project == null) { - throw new HttpClientErrorException(HttpStatus.NOT_FOUND, "Project " + project_id + " not found."); - } - - this.checkCowebkey(cowebkey, project, EditMode.EDITION); - - Map model = new HashMap(); - model.put("coweb_debug", Boolean.parseBoolean(RenkanProperties.getInstance().getProperty("renkan.coweb.debug","false"))); - model.put("coweb_websockets", Boolean.parseBoolean(RenkanProperties.getInstance().getProperty("renkan.coweb.websocket", "true"))); - model.put("project", project); - model.put("space", spacesRepository.findOne(project.getSpaceId())); - - return new ModelAndView("renkanProjectEdit", model); - } - - @RequestMapping(value="/pub/{project_id}", method = RequestMethod.GET, produces={"text/html;charset=UTF-8", "!image/*"}) - public String renkanPublishProject( - Model model, - @PathVariable(value="project_id") String project_id, - @RequestParam(value="cowebkey") String cowebkey - ) - { - if(project_id == null || project_id.length() == 0) { - throw new IllegalArgumentException("RenkanContoller.renkanProject: Project id is null or empty."); - } - - Project project = this.projectsRepository.findOne(project_id); - if(project == null) { - throw new HttpClientErrorException(HttpStatus.NOT_FOUND, "Project " + project_id + " not found."); - } + this.logger.debug("renkanProject : " + project_id + " Accept : " + + accept_header != null ? accept_header : "" + ", cowebkey: " + + cowebkey != null ? cowebkey : ""); + + if (project_id == null || project_id.length() == 0) { + throw new IllegalArgumentException( + "RenkanContoller.renkanProject: Project id is null or empty."); + } + + Project project = this.projectsRepository.findOne(project_id); + + if (project == null) { + throw new HttpClientErrorException(HttpStatus.NOT_FOUND, "Project " + + project_id + " not found."); + } + + this.checkCowebkey(cowebkey, project, EditMode.EDITION); + + Map model = new HashMap(); + model.put("coweb_debug", Boolean.parseBoolean(RenkanProperties + .getInstance().getProperty("renkan.coweb.debug", "false"))); + model.put("coweb_websockets", Boolean.parseBoolean(RenkanProperties + .getInstance().getProperty("renkan.coweb.websocket", "true"))); + model.put("project", project); + model.put("space", spacesRepository.findOne(project.getSpaceId())); - this.checkCowebkey(cowebkey, project, EditMode.READ_ONLY); - - model.addAttribute("project", project); - model.addAttribute("space", spacesRepository.findOne(project.getSpaceId())); - - return "renkanProjectPublish"; - } - - + return new ModelAndView("renkanProjectEdit", model); + } + + @RequestMapping(value = "/pub/{project_id}", method = RequestMethod.GET, produces = { + "text/html;charset=UTF-8", "!image/*" }) + public String renkanPublishProject(Model model, + @PathVariable(value = "project_id") String project_id, + @RequestParam(value = "cowebkey") String cowebkey) { + if (project_id == null || project_id.length() == 0) { + throw new IllegalArgumentException( + "RenkanContoller.renkanProject: Project id is null or empty."); + } + + Project project = this.projectsRepository.findOne(project_id); + if (project == null) { + throw new HttpClientErrorException(HttpStatus.NOT_FOUND, "Project " + + project_id + " not found."); + } + + this.checkCowebkey(cowebkey, project, EditMode.READ_ONLY); + + model.addAttribute("project", project); + model.addAttribute("space", + spacesRepository.findOne(project.getSpaceId())); + + return "renkanProjectPublish"; + } + } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/controller/RenkanRootController.java --- a/server/src/main/java/org/iri_research/renkan/controller/RenkanRootController.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/controller/RenkanRootController.java Wed Jan 15 18:36:27 2014 +0100 @@ -16,7 +16,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort.Direction; -import org.springframework.data.web.PageableDefaults; +import org.springframework.data.web.PageableDefault; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; @@ -27,62 +27,70 @@ import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.servlet.ModelAndView; - @Controller @RequestMapping("/") public class RenkanRootController { - private final Logger logger = LoggerFactory.getLogger(RenkanRootController.class); - - @Autowired - private ProjectsRepository projectsRepository; - - @Autowired - private SpacesRepository spacesRepository; - - @RequestMapping(value="", method = RequestMethod.GET, produces={"text/html;charset=UTF-8"}) - public String renkanIndex(Model model, @PageableDefaults(sort={"created"}, sortDir=Direction.DESC, pageNumber=0, value=Constants.PAGINATION_SIZE) Pageable p, HttpServletRequest request) { + private final Logger logger = LoggerFactory + .getLogger(RenkanRootController.class); + + @Autowired + private ProjectsRepository projectsRepository; + + @Autowired + private SpacesRepository spacesRepository; + + @RequestMapping(value = "", method = RequestMethod.GET, produces = { "text/html;charset=UTF-8" }) + public String renkanIndex( + Model model, + @PageableDefault(sort = { "created" }, direction = Direction.DESC, page = 0, value = Constants.PAGINATION_SIZE) Pageable p, + HttpServletRequest request) { - Page page = this.spacesRepository.findAll(p); - - model.addAttribute("page", page); - model.addAttribute("baseUrl", Utils.buildBaseUrl(request)); - model.addAttribute("projectsCount", this.projectsRepository.getCountBySpace()); - - return "renkanIndex"; - } + Page page = this.spacesRepository.findAll(p); + + model.addAttribute("page", page); + model.addAttribute("baseUrl", Utils.buildBaseUrl(request)); + model.addAttribute("projectsCount", + this.projectsRepository.getCountBySpace()); - @RequestMapping(value="/s/{space_id}", method = RequestMethod.GET, produces={"text/html;charset=UTF-8"}) - public ModelAndView spaceIndex(@PathVariable("space_id") String spaceId, @RequestParam(required=false) String filter, @PageableDefaults(sort={"updated","created"}, sortDir=Direction.DESC, pageNumber=0, value=Constants.PAGINATION_SIZE) Pageable p, HttpServletRequest request) { - - logger.debug("SpaceId : " + (spaceId== null ? "null" : spaceId)); - - Map model = new HashMap(); + return "renkanIndex"; + } + + @RequestMapping(value = "/s/{space_id}", method = RequestMethod.GET, produces = { "text/html;charset=UTF-8" }) + public ModelAndView spaceIndex( + @PathVariable("space_id") String spaceId, + @RequestParam(required = false) String filter, + @PageableDefault(sort = { "updated", "created" }, direction = Direction.DESC, page = 0, value = Constants.PAGINATION_SIZE) Pageable p, + HttpServletRequest request) { - if("_".equals(spaceId)) { - spaceId = null; - } - - Space space = this.spacesRepository.findOne(spaceId); - - if(null == space) { - throw new HttpClientErrorException(HttpStatus.NOT_FOUND, "Space " + spaceId + " not found."); - } - - model.put("space", space); - Page page; - if(filter != null && !filter.isEmpty()) { - page = this.projectsRepository.findBySpaceIdAndTitleRegex(spaceId, filter, p); - } - else { - page = this.projectsRepository.findBySpaceId(spaceId, p); - } - - model.put("page", page); - model.put("baseUrl", Utils.buildBaseUrl(request)); - - return new ModelAndView("projectIndex", model); - } - - + logger.debug("SpaceId : " + (spaceId == null ? "null" : spaceId)); + + Map model = new HashMap(); + + if ("_".equals(spaceId)) { + spaceId = null; + } + + Space space = this.spacesRepository.findOne(spaceId); + + if (null == space) { + throw new HttpClientErrorException(HttpStatus.NOT_FOUND, "Space " + + spaceId + " not found."); + } + + model.put("space", space); + Page page; + if (filter != null && !filter.isEmpty()) { + page = this.projectsRepository.findBySpaceIdAndTitleRegex(spaceId, + filter, p); + } else { + page = this.projectsRepository.findBySpaceId(spaceId, p); + } + + model.put("page", page); + model.put("baseUrl", Utils.buildBaseUrl(request)); + + return new ModelAndView("projectIndex", model); + } + } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/controller/Utils.java --- a/server/src/main/java/org/iri_research/renkan/controller/Utils.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/controller/Utils.java Wed Jan 15 18:36:27 2014 +0100 @@ -5,29 +5,27 @@ import javax.servlet.http.HttpServletRequest; public class Utils { - - public static String buildBaseUrl(HttpServletRequest request) { - StringBuffer baseUrl = request.getRequestURL(); - boolean firstParam = true; - Enumeration namesEnum = request.getParameterNames(); - while(namesEnum.hasMoreElements()) { - String paramName = - (String)namesEnum.nextElement(); - - if("p.page".equals(paramName)) { - continue; - } - for(String val:request.getParameterValues(paramName)) { - if(firstParam) { - baseUrl.append('?'); - firstParam = false; - } - else { - baseUrl.append('&'); - } - baseUrl.append(paramName).append('=').append(val); - } - } - return baseUrl.toString(); - } + + public static String buildBaseUrl(HttpServletRequest request) { + StringBuffer baseUrl = request.getRequestURL(); + boolean firstParam = true; + Enumeration namesEnum = request.getParameterNames(); + while (namesEnum.hasMoreElements()) { + String paramName = (String) namesEnum.nextElement(); + + if ("p.page".equals(paramName)) { + continue; + } + for (String val : request.getParameterValues(paramName)) { + if (firstParam) { + baseUrl.append('?'); + firstParam = false; + } else { + baseUrl.append('&'); + } + baseUrl.append(paramName).append('=').append(val); + } + } + return baseUrl.toString(); + } } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/controller/admin/AbstractRenkanObjectAdminController.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/java/org/iri_research/renkan/controller/admin/AbstractRenkanObjectAdminController.java Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,5 @@ +package org.iri_research.renkan.controller.admin; + +public abstract class AbstractRenkanObjectAdminController { + +} diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/controller/admin/AdminController.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/java/org/iri_research/renkan/controller/admin/AdminController.java Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,22 @@ +package org.iri_research.renkan.controller.admin; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +@Controller +@RequestMapping("/admin") +public class AdminController { + + @SuppressWarnings("unused") + private final Logger logger = LoggerFactory + .getLogger(AdminController.class); + + @RequestMapping(value = "", method = RequestMethod.GET, produces = { "text/html;charset=UTF-8" }) + public String adminIndex() { + return "admin/adminIndex"; + } + +} diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/controller/admin/GroupsAdminController.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/java/org/iri_research/renkan/controller/admin/GroupsAdminController.java Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,193 @@ +package org.iri_research.renkan.controller.admin; + +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Locale; + +import javax.inject.Inject; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; + +import org.apache.commons.codec.binary.Hex; +import org.iri_research.renkan.Constants; +import org.iri_research.renkan.RenkanException; +import org.iri_research.renkan.controller.Utils; +import org.iri_research.renkan.forms.GroupForm; +import org.iri_research.renkan.forms.GroupFormValidator; +import org.iri_research.renkan.models.Group; +import org.iri_research.renkan.repositories.GroupsRepository; +import org.iri_research.renkan.repositories.UsersRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.propertyeditors.StringTrimmerEditor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort.Direction; +import org.springframework.data.web.PageableDefault; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.InitBinder; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.client.HttpClientErrorException; + +@Controller +@RequestMapping("/admin/groups") +public class GroupsAdminController { + + private final Logger logger = LoggerFactory + .getLogger(GroupsAdminController.class); + + @Inject + private GroupsRepository groupsRepository; + + @Inject + private UsersRepository usersRepository; + + + @InitBinder(value = { "group" }) + protected void initBinder(WebDataBinder binder) { + binder.setValidator(new GroupFormValidator()); + } + + @InitBinder + public void initDateBinder(final WebDataBinder dataBinder, final Locale locale) { + dataBinder.registerCustomEditor(String.class, new StringTrimmerEditor(true)); + } + + @RequestMapping(value = "", method = RequestMethod.GET, produces = { "text/html;charset=UTF-8" }) + public String groupsList( + Model model, + @PageableDefault(sort = { "title" }, direction = Direction.DESC, page = 0, value = Constants.PAGINATION_SIZE) Pageable p, + HttpServletRequest request) { + + Page page = this.groupsRepository.findAll(p); + + model.addAttribute("page", page); + model.addAttribute("baseUrl", Utils.buildBaseUrl(request)); + //TODO: add user count + + return "admin/groupsList"; + } + + @RequestMapping(value = "/edit/", method = RequestMethod.GET, produces = { "text/html;charset=UTF-8" }) + public String editGroup(Model model) { + return editGroup(model, null); + } + + @RequestMapping(value = "/edit/{groupId}", method = RequestMethod.GET, produces = { "text/html;charset=UTF-8" }) + public String editGroup(Model model, + @PathVariable(value = "groupId") String groupId) { + + GroupForm groupForm = null; + Group group = null; + + if (groupId != null && groupId.length() > 0 && !"_".equals(groupId)) { + group = this.groupsRepository.findOne(groupId); + if (group == null) { + throw new HttpClientErrorException(HttpStatus.NOT_FOUND, + "group " + groupId + " not found"); + } + } + groupForm = new GroupForm(group); + + model.addAttribute("group", groupForm); + model.addAttribute("allUsers", this.usersRepository.findAll()); + + return "admin/groupEdit"; + } + + @RequestMapping(value = "/save", method = RequestMethod.POST) + public String saveGroup(Model model, + @ModelAttribute("group") @Valid GroupForm groupForm, + BindingResult bindingResult) { + + logger.debug("group title " + groupForm.getTitle()); + logger.debug("user description " + groupForm.getDescription()); + + if (bindingResult.hasErrors()) { + return "admin/groupEdit"; + } + + groupForm.setGroupsRepository(groupsRepository); + + try { + groupForm.save(); + } catch (RenkanException e) { + throw new HttpClientErrorException(HttpStatus.NOT_FOUND, "group " + + groupForm.getId()==null?"":groupForm.getId() + " not found"); + } + + return "redirect:/admin/groups"; + } + + @RequestMapping(value = "/delete/{groupId}") + public String deleteGroup(HttpServletRequest request, Model model, + @PathVariable(value = "groupId") String groupId, + @RequestParam(value = "key", required = false) String key, + @RequestParam(value = "salt", required = false) String salt) + throws NoSuchAlgorithmException, RenkanException { + + if (groupId == null || groupId.length() == 0) { + throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, + "Null or empty user id"); + } + + RequestMethod method = RequestMethod.valueOf(request.getMethod()); + + //TODO: check that group have no user + + + if (RequestMethod.GET.equals(method)) { + + Group group = this.groupsRepository.findOne(groupId); + + if (group == null) { + throw new HttpClientErrorException(HttpStatus.NOT_FOUND, + "group " + groupId + " not found"); + } + + SecureRandom rand = SecureRandom.getInstance("SHA1PRNG"); + rand.setSeed(System.currentTimeMillis()); + byte[] rawSalt = new byte[50]; + rand.nextBytes(rawSalt); + String newSalt = Hex.encodeHexString(rawSalt); + + model.addAttribute("groupObj", group); + model.addAttribute("salt", newSalt); + model.addAttribute("key", group.getKey(newSalt)); + + return "admin/groupDeleteConfirm"; + + } else if (RequestMethod.POST.equals(method) && key != null + && !key.isEmpty() && salt != null && !salt.isEmpty()) { + + if (groupId != null && groupId.length() > 0) { + + Group group = this.groupsRepository.findOne(groupId); + if (group != null) { + if (group.checkKey(key, salt)) { + this.groupsRepository.delete(groupId); + } else { + throw new HttpClientErrorException( + HttpStatus.BAD_REQUEST, "Key not ckecked"); + } + } + + } + return "redirect:/admin/groups"; + + } else { + throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, + "Bad request method or parameters"); + } + + } + +} diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/controller/admin/SpacesAdminController.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/java/org/iri_research/renkan/controller/admin/SpacesAdminController.java Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,190 @@ +package org.iri_research.renkan.controller.admin; + +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; + +import org.apache.commons.codec.binary.Hex; +import org.iri_research.renkan.Constants; +import org.iri_research.renkan.RenkanException; +import org.iri_research.renkan.controller.Utils; +import org.iri_research.renkan.forms.SpaceForm; +import org.iri_research.renkan.forms.SpaceFormValidator; +import org.iri_research.renkan.models.Space; +import org.iri_research.renkan.repositories.ProjectsRepository; +import org.iri_research.renkan.repositories.SpacesRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort.Direction; +import org.springframework.data.web.PageableDefault; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.InitBinder; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.client.HttpClientErrorException; + +@Controller +@RequestMapping("/admin/spaces") +public class SpacesAdminController { + + private final Logger logger = LoggerFactory + .getLogger(SpacesAdminController.class); + + @Autowired + private SpacesRepository spacesRepository; + @Autowired + private ProjectsRepository projectsRepository; + + @InitBinder(value = { "space" }) + protected void initBinder(WebDataBinder binder) { + binder.setValidator(new SpaceFormValidator()); + } + + @RequestMapping(value = "", method = RequestMethod.GET, produces = { "text/html;charset=UTF-8" }) + public String spacesList( + Model model, + @PageableDefault(sort = { "created" }, direction = Direction.DESC, page = 0, value = Constants.PAGINATION_SIZE) Pageable p, + HttpServletRequest request) { + + Page page = this.spacesRepository.findAll(p); + + model.addAttribute("page", page); + model.addAttribute("baseUrl", Utils.buildBaseUrl(request)); + model.addAttribute("projectsCount", + this.projectsRepository.getCountBySpace()); + + return "admin/spacesList"; + } + + @RequestMapping(value = "/edit/", method = RequestMethod.GET, produces = { "text/html;charset=UTF-8" }) + public String editSpace(Model model) { + return editSpace(model, null); + } + + @RequestMapping(value = "/edit/{spaceId}", method = RequestMethod.GET, produces = { "text/html;charset=UTF-8" }) + public String editSpace(Model model, + @PathVariable(value = "spaceId") String spaceId) { + + SpaceForm spaceForm = null; + + if (spaceId == null || spaceId.length() == 0 || "_".equals(spaceId)) { + spaceForm = new SpaceForm(); + } else { + Space space = this.spacesRepository.findOne(spaceId); + if (space == null) { + throw new HttpClientErrorException(HttpStatus.NOT_FOUND, + "space " + spaceId + " not found"); + } + spaceForm = new SpaceForm(space); + } + + model.addAttribute("space", spaceForm); + + return "admin/spaceEdit"; + } + + @RequestMapping(value = "/save", method = RequestMethod.POST) + public String saveSpace(Model model, + @ModelAttribute("space") @Valid SpaceForm spaceForm, + BindingResult bindingResult) { + + logger.debug("space title " + spaceForm.getTitle()); + logger.debug("space description " + spaceForm.getDescription()); + + if (bindingResult.hasErrors()) { + return "admin/spaceEdit"; + } + + spaceForm.setSpacesRepository(spacesRepository); + + try { + spaceForm.save(); + } catch (RenkanException e) { + throw new HttpClientErrorException(HttpStatus.NOT_FOUND, "space " + + spaceForm.getId() + " not found"); + } + + return "redirect:/admin/spaces"; + } + + @RequestMapping(value = "/delete/{spaceId}") + public String deleteSpace(HttpServletRequest request, Model model, + @PathVariable(value = "spaceId") String spaceId, + @RequestParam(value = "key", required = false) String key, + @RequestParam(value = "salt", required = false) String salt) + throws NoSuchAlgorithmException, RenkanException { + + if (spaceId == null || spaceId.length() == 0) { + throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, + "Null or empty space id"); + } + + RequestMethod method = RequestMethod.valueOf(request.getMethod()); + + Map nbProj = this.projectsRepository + .getCountBySpace(Arrays.asList(spaceId)); + if (nbProj.containsKey(spaceId) && nbProj.get(spaceId).intValue() > 0) { + throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, + "This space have projects"); + } + + if (RequestMethod.GET.equals(method)) { + + Space space = this.spacesRepository.findOne(spaceId); + + if (space == null) { + throw new HttpClientErrorException(HttpStatus.NOT_FOUND, + "space " + spaceId + " not found"); + } + + SecureRandom rand = SecureRandom.getInstance("SHA1PRNG"); + rand.setSeed(System.currentTimeMillis()); + byte[] rawSalt = new byte[50]; + rand.nextBytes(rawSalt); + String newSalt = Hex.encodeHexString(rawSalt); + + model.addAttribute("spaceObj", space); + model.addAttribute("salt", newSalt); + model.addAttribute("key", space.getKey(newSalt)); + + return "admin/spaceDeleteConfirm"; + } else if (RequestMethod.POST.equals(method) && key != null + && !key.isEmpty() && salt != null && !salt.isEmpty()) { + + if (spaceId != null && spaceId.length() > 0) { + + Space space = this.spacesRepository.findOne(spaceId); + if (space != null) { + if (space.checkKey(key, salt)) { + this.spacesRepository.delete(spaceId); + } else { + throw new HttpClientErrorException( + HttpStatus.BAD_REQUEST, "Key not ckecked"); + } + } + + } + return "redirect:/admin/spaces"; + + } else { + throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, + "Bad request method or parameters"); + } + + } + +} diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/controller/admin/UsersAdminController.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/java/org/iri_research/renkan/controller/admin/UsersAdminController.java Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,209 @@ +package org.iri_research.renkan.controller.admin; + +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.Locale; +import java.util.Map; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; + +import org.apache.commons.codec.binary.Hex; +import org.iri_research.renkan.Constants; +import org.iri_research.renkan.RenkanException; +import org.iri_research.renkan.controller.Utils; +import org.iri_research.renkan.forms.UserForm; +import org.iri_research.renkan.forms.UserFormValidator; +import org.iri_research.renkan.models.User; +import org.iri_research.renkan.repositories.GroupsRepository; +import org.iri_research.renkan.repositories.ProjectsRepository; +import org.iri_research.renkan.repositories.UsersRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.propertyeditors.StringTrimmerEditor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort.Direction; +import org.springframework.data.web.PageableDefault; +import org.springframework.http.HttpStatus; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.InitBinder; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.client.HttpClientErrorException; + +@Controller +@RequestMapping("/admin/users") +public class UsersAdminController { + + private final Logger logger = LoggerFactory + .getLogger(UsersAdminController.class); + + @Inject + private UsersRepository usersRepository; + + @Inject + private ProjectsRepository projectsRepository; + + @Inject + private GroupsRepository groupsRepository; + + @Resource(name="renkanPasswordEncoder") + private PasswordEncoder passwordEncoder; + + @InitBinder(value = { "user" }) + protected void initBinder(WebDataBinder binder) { + binder.setValidator(new UserFormValidator()); + } + + @InitBinder + public void initDateBinder(final WebDataBinder dataBinder, final Locale locale) { + dataBinder.registerCustomEditor(String.class, new StringTrimmerEditor(true)); + } + + @RequestMapping(value = "", method = RequestMethod.GET, produces = { "text/html;charset=UTF-8" }) + public String usersList( + Model model, + @PageableDefault(sort = { "username" }, direction = Direction.DESC, page = 0, value = Constants.PAGINATION_SIZE) Pageable p, + HttpServletRequest request) { + + Page page = this.usersRepository.findAll(p); + + model.addAttribute("page", page); + model.addAttribute("baseUrl", Utils.buildBaseUrl(request)); + model.addAttribute("projectsCount", + this.projectsRepository.getCountByUser()); + + return "admin/usersList"; + } + + @RequestMapping(value = "/edit/", method = RequestMethod.GET, produces = { "text/html;charset=UTF-8" }) + public String editUser(Model model) { + return editUser(model, null); + } + + @RequestMapping(value = "/edit/{userId}", method = RequestMethod.GET, produces = { "text/html;charset=UTF-8" }) + public String editUser(Model model, + @PathVariable(value = "userId") String userId) { + + UserForm userForm = null; + User user = null; + + if (userId != null && userId.length() > 0 && !"_".equals(userId)) { + user = this.usersRepository.findOne(userId); + if (user == null) { + throw new HttpClientErrorException(HttpStatus.NOT_FOUND, + "user " + userId + " not found"); + } + } + userForm = new UserForm(user); + + model.addAttribute("user", userForm); + model.addAttribute("allGroups", this.groupsRepository.findAll()); + + return "admin/userEdit"; + } + + @RequestMapping(value = "/save", method = RequestMethod.POST) + public String saveUser(Model model, + @ModelAttribute("user") @Valid UserForm userForm, + BindingResult bindingResult) { + + logger.debug("user title " + userForm.getTitle()); + logger.debug("user description " + userForm.getDescription()); + + if (bindingResult.hasErrors()) { + return "admin/userEdit"; + } + + userForm.setUsersRepository(usersRepository); + userForm.setPasswordEncoder(passwordEncoder); + + try { + userForm.save(); + } catch (RenkanException e) { + throw new HttpClientErrorException(HttpStatus.NOT_FOUND, "user " + + userForm.getId()==null?"":userForm.getId() + " not found"); + } + + return "redirect:/admin/users"; + } + + @RequestMapping(value = "/delete/{userId}") + public String deleteUser(HttpServletRequest request, Model model, + @PathVariable(value = "userId") String userId, + @RequestParam(value = "key", required = false) String key, + @RequestParam(value = "salt", required = false) String salt) + throws NoSuchAlgorithmException, RenkanException { + + if (userId == null || userId.length() == 0) { + throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, + "Null or empty user id"); + } + + RequestMethod method = RequestMethod.valueOf(request.getMethod()); + + Map nbProj = this.projectsRepository + .getCountByUser(Arrays.asList(userId)); + if (nbProj.containsKey(userId) && nbProj.get(userId).intValue() > 0) { + throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, + "This user have projects"); + } + + if (RequestMethod.GET.equals(method)) { + + User user = this.usersRepository.findOne(userId); + + if (user == null) { + throw new HttpClientErrorException(HttpStatus.NOT_FOUND, + "user " + userId + " not found"); + } + + SecureRandom rand = SecureRandom.getInstance("SHA1PRNG"); + rand.setSeed(System.currentTimeMillis()); + byte[] rawSalt = new byte[50]; + rand.nextBytes(rawSalt); + String newSalt = Hex.encodeHexString(rawSalt); + + model.addAttribute("userObj", user); + model.addAttribute("salt", newSalt); + model.addAttribute("key", user.getKey(newSalt)); + + return "admin/userDeleteConfirm"; + + } else if (RequestMethod.POST.equals(method) && key != null + && !key.isEmpty() && salt != null && !salt.isEmpty()) { + + if (userId != null && userId.length() > 0) { + + User user = this.usersRepository.findOne(userId); + if (user != null) { + if (user.checkKey(key, salt)) { + this.usersRepository.delete(userId); + } else { + throw new HttpClientErrorException( + HttpStatus.BAD_REQUEST, "Key not ckecked"); + } + } + + } + return "redirect:/admin/users"; + + } else { + throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, + "Bad request method or parameters"); + } + + } + +} diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/coweb/RenkanSessionModerator.java --- a/server/src/main/java/org/iri_research/renkan/coweb/RenkanSessionModerator.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/coweb/RenkanSessionModerator.java Wed Jan 15 18:36:27 2014 +0100 @@ -16,210 +16,256 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.joda.JodaModule; public class RenkanSessionModerator extends DefaultSessionModerator { - - private final Logger logger = LoggerFactory.getLogger(RenkanSessionModerator.class); - - private ProjectsRepository projectsRepository; - - - public RenkanSessionModerator() { - super(); - } - - public ProjectsRepository getProjectsRepository() { - if(this.projectsRepository == null) { - ApplicationContext context = SpringConfigurer.getInstance().getApplicationContext(); - this.projectsRepository = (ProjectsRepository)context.getBean("projectsRepository"); - } - return projectsRepository; - } + + private final Logger logger = LoggerFactory + .getLogger(RenkanSessionModerator.class); + + private ProjectsRepository projectsRepository; + + public RenkanSessionModerator() { + super(); + } + + public ProjectsRepository getProjectsRepository() { + if (this.projectsRepository == null) { + ApplicationContext context = SpringConfigurer.getInstance() + .getApplicationContext(); + this.projectsRepository = (ProjectsRepository) context + .getBean("projectsRepository"); + } + return projectsRepository; + } + + @Override + public synchronized boolean canClientJoinSession(String clientId, + Map userDefined) { + + this.logger.debug("canClientJoinSession: " + clientId + " , " + + (userDefined == null ? "null" : userDefined.toString())); + + if (RenkanSessionModeratorState.INSTANCE.getUsersActivationMap() + .containsKey(clientId)) { + this.logger + .warn("Client id already declared in user activation map: " + + clientId); + } + + String projectId = (String) userDefined.get("project_id"); + + if (projectId == null) { + return false; + } + + RenkanSessionModeratorState.INSTANCE.getUsersActivationMap().put( + clientId, projectId); + return true; + } + + private synchronized void activateProject(String clientId) { - @Override - public synchronized boolean canClientJoinSession(String clientId, Map userDefined) { - - this.logger.debug("canClientJoinSession: " + clientId + " , " + (userDefined==null?"null":userDefined.toString())); - - if(RenkanSessionModeratorState.INSTANCE.getUsersActivationMap().containsKey(clientId)) { - this.logger.warn("Client id already declared in user activation map: " + clientId); - } - - String projectId = (String)userDefined.get("project_id"); - - if(projectId == null) { - return false; - } - - RenkanSessionModeratorState.INSTANCE.getUsersActivationMap().put(clientId, projectId); - return true; - } - - private synchronized void activateProject(String clientId) { - - if(!RenkanSessionModeratorState.INSTANCE.getUsersActivationMap().containsKey(clientId)) { - this.logger.warn("Client id not declared in user activation map: " + clientId); - return; - } - String project_id = RenkanSessionModeratorState.INSTANCE.getUsersActivationMap().get(clientId); - if(project_id == null) { - this.logger.warn("Null project id for client id in user activation map: " + clientId); - return; - } - - List user_list = RenkanSessionModeratorState.INSTANCE.getProjectsActivationMap().get(project_id); - if(user_list == null) { - user_list = new ArrayList(); - RenkanSessionModeratorState.INSTANCE.getProjectsActivationMap().put(project_id, user_list); - } + if (!RenkanSessionModeratorState.INSTANCE.getUsersActivationMap() + .containsKey(clientId)) { + this.logger.warn("Client id not declared in user activation map: " + + clientId); + return; + } + String project_id = RenkanSessionModeratorState.INSTANCE + .getUsersActivationMap().get(clientId); + if (project_id == null) { + this.logger + .warn("Null project id for client id in user activation map: " + + clientId); + return; + } + + List user_list = RenkanSessionModeratorState.INSTANCE + .getProjectsActivationMap().get(project_id); + if (user_list == null) { + user_list = new ArrayList(); + RenkanSessionModeratorState.INSTANCE.getProjectsActivationMap() + .put(project_id, user_list); + } + + if (!user_list.contains(clientId)) { + user_list.add(clientId); + } + + } + + @Override + public synchronized void onClientJoinSession(String clientId) { + + this.logger.debug("onClientJoinSession: " + clientId); - if(!user_list.contains(clientId)) { - user_list.add(clientId); - } + this.activateProject(clientId); + + } + + @Override + public synchronized void onClientLeaveSession(String clientId) { + + this.logger.debug("onClientLeaveSession: " + clientId); + + String project_id = RenkanSessionModeratorState.INSTANCE + .getUsersActivationMap().get(clientId); + + RenkanSessionModeratorState.INSTANCE.getUsersActivationMap().remove( + clientId); + if (project_id == null) { + this.logger.warn("Leaving client have no associated project: " + + clientId); + return; + } + + List user_list = RenkanSessionModeratorState.INSTANCE + .getProjectsActivationMap().get(project_id); + if (user_list == null) { + this.logger + .warn("Leaving client have associated project but no project list : " + + clientId + ", " + project_id); + return; + } + + if (!user_list.remove(clientId)) { + this.logger + .warn("Leaving client have associated project but not in project list : " + + clientId + ", " + project_id); + return; + } - } - - @Override - public synchronized void onClientJoinSession(String clientId) { - - this.logger.debug("onClientJoinSession: " + clientId); - - this.activateProject(clientId); - - } - - @Override - public synchronized void onClientLeaveSession(String clientId) { - - this.logger.debug("onClientLeaveSession: " + clientId); - - String project_id = RenkanSessionModeratorState.INSTANCE.getUsersActivationMap().get(clientId); - - RenkanSessionModeratorState.INSTANCE.getUsersActivationMap().remove(clientId); - if(project_id == null) { - this.logger.warn("Leaving client have no associated project: " + clientId); - return; - } - - List user_list = RenkanSessionModeratorState.INSTANCE.getProjectsActivationMap().get(project_id); - if(user_list == null) { - this.logger.warn("Leaving client have associated project but no project list : " + clientId + ", " + project_id); - return; - } - - if(!user_list.remove(clientId)) { - this.logger.warn("Leaving client have associated project but not in project list : " + clientId + ", " + project_id); - return; - } - - if(user_list.isEmpty()) { - this.logger.debug("Leaving client, project list empty, removing from active projects: " + clientId + ", " + project_id); - RenkanSessionModeratorState.INSTANCE.getProjectsActivationMap().remove(project_id); - } - - List r_user_list = RenkanSessionModeratorState.INSTANCE.getProjectsUsersList().get(project_id); - if(r_user_list == null) { - this.logger.warn("Leaving client have associated project but no user list : " + clientId + ", " + project_id); - return; - } - for (RosterUser rosterUser : r_user_list) { - if( rosterUser.getClient_id().equals(clientId)) { - r_user_list.remove(rosterUser); - } - } - if(r_user_list.isEmpty()) { - this.logger.debug("Leaving client, user list empty, removing from active projects: " + clientId + ", " + project_id); - RenkanSessionModeratorState.INSTANCE.getProjectsUsersList().remove(project_id); - } - - } - - @SuppressWarnings("unchecked") - @Override - public synchronized void onSync(String clientId, Map data) { - - this.logger.debug("Debugging onSync client id: " + clientId); - this.logger.debug("Debugging onSync: " + data.toString()); - this.logger.debug("Debugging onSync channel: " + data.get("channel")); - this.logger.debug("Debugging onSync type: " + data.get("type")); - this.logger.debug("Debugging onSync site: " + data.get("site")); - this.logger.debug("Debugging onSync value: " + data.get("value")); - this.logger.debug("Debugging onSync position: " + data.get("position")); - - Map values = null; - if(data.containsKey("value") && data.get("value") != null) { - values = ((Map) data.get("value")); - } - - if(values == null) { - this.logger.warn("onSync : no values in message."); - return; - } - - String sync_type = (String) values.get("_type"); - if(sync_type == null || sync_type.length() == 0) { - this.logger.warn("onSync : no type in value of message."); - return; - } - - if(sync_type.startsWith("_")) { - this.logger.debug("onSync : type sync begin with _, ignore. " + sync_type); - return; - } - - ApplicationContext context = SpringConfigurer.getInstance().getApplicationContext(); - - String beanName = String.format("%sSyncEventManager", sync_type.toLowerCase()); - - try { - ISyncEventManager eventManager = (ISyncEventManager)context.getBean(beanName); - logger.debug("Debugging on Sync : dispatch to " + beanName); - eventManager.dispatchEvent(clientId, data); - } - catch(Throwable e) { - this.logger.error(String.format("onSync EventManagerClass %s not found : error %s : %s", sync_type, e.toString(), e.getMessage())); - } - - } + if (user_list.isEmpty()) { + this.logger + .debug("Leaving client, project list empty, removing from active projects: " + + clientId + ", " + project_id); + RenkanSessionModeratorState.INSTANCE.getProjectsActivationMap() + .remove(project_id); + } + + List r_user_list = RenkanSessionModeratorState.INSTANCE + .getProjectsUsersList().get(project_id); + if (r_user_list == null) { + this.logger + .warn("Leaving client have associated project but no user list : " + + clientId + ", " + project_id); + return; + } + for (RosterUser rosterUser : r_user_list) { + if (rosterUser.getClientId().equals(clientId)) { + r_user_list.remove(rosterUser); + } + } + if (r_user_list.isEmpty()) { + this.logger + .debug("Leaving client, user list empty, removing from active projects: " + + clientId + ", " + project_id); + RenkanSessionModeratorState.INSTANCE.getProjectsUsersList().remove( + project_id); + } + + } + + @SuppressWarnings("unchecked") + @Override + public synchronized void onSync(String clientId, Map data) { + + this.logger.debug("Debugging onSync client id: " + clientId); + this.logger.debug("Debugging onSync: " + data.toString()); + this.logger.debug("Debugging onSync channel: " + data.get("channel")); + this.logger.debug("Debugging onSync type: " + data.get("type")); + this.logger.debug("Debugging onSync site: " + data.get("site")); + this.logger.debug("Debugging onSync value: " + data.get("value")); + this.logger.debug("Debugging onSync position: " + data.get("position")); + + Map values = null; + if (data.containsKey("value") && data.get("value") != null) { + values = ((Map) data.get("value")); + } + + if (values == null) { + this.logger.warn("onSync : no values in message."); + return; + } + + String sync_type = (String) values.get("_type"); + if (sync_type == null || sync_type.length() == 0) { + this.logger.warn("onSync : no type in value of message."); + return; + } + + if (sync_type.startsWith("_")) { + this.logger.debug("onSync : type sync begin with _, ignore. " + + sync_type); + return; + } - @Override - public Map getLateJoinState() { - this.logger.debug("getLateJoinState"); - - Map res = super.getLateJoinState(); - ObjectMapper mapper = new ObjectMapper(); - - for (String clientId : RenkanSessionModeratorState.INSTANCE.getUsersActivationMap().keySet()) { - this.activateProject(clientId); - } - - this.logger.debug("getLateJoinState : Project activated"); - - for (String project_id : RenkanSessionModeratorState.INSTANCE.getProjectsActivationMap().keySet()) { + ApplicationContext context = SpringConfigurer.getInstance() + .getApplicationContext(); + + String beanName = String.format("%sSyncEventManager", + sync_type.toLowerCase()); + + try { + ISyncEventManager eventManager = (ISyncEventManager) context + .getBean(beanName); + logger.debug("Debugging on Sync : dispatch to " + beanName); + eventManager.dispatchEvent(clientId, data); + } catch (Throwable e) { + this.logger.error(String.format( + "onSync EventManagerClass %s not found : error %s : %s", + sync_type, e.toString(), e.getMessage())); + } + + } + + @Override + public Map getLateJoinState() { + this.logger.debug("getLateJoinState"); + + Map res = super.getLateJoinState(); + ObjectMapper mapper = new ObjectMapper(); + mapper.registerModule(new JodaModule()); + + for (String clientId : RenkanSessionModeratorState.INSTANCE + .getUsersActivationMap().keySet()) { + this.activateProject(clientId); + } - Project p = this.getProjectsRepository().findOne(project_id); - if (p != null) { - try { - res.put("renkan_"+project_id, mapper.writeValueAsString(p)); - } catch (JsonProcessingException e) { - this.logger.error("Error when deserializing project " + project_id, e); - } - } - - String user_res = "[]"; - if(RenkanSessionModeratorState.INSTANCE.getProjectsUsersList().containsKey(project_id)) { - try { - user_res = mapper.writeValueAsString(RenkanSessionModeratorState.INSTANCE.getProjectsUsersList().get(project_id)); - } catch (JsonProcessingException e) { - this.logger.error("Error when deserializing user list " + project_id, e); - } - } - res.put("users_"+project_id, user_res); - } - - - this.logger.debug("getLateJoinState res : " + res.toString()); - return res; - } + this.logger.debug("getLateJoinState : Project activated"); + + for (String project_id : RenkanSessionModeratorState.INSTANCE + .getProjectsActivationMap().keySet()) { + + Project p = this.getProjectsRepository().findOne(project_id); + if (p != null) { + try { + res.put("renkan_" + project_id, + mapper.writeValueAsString(p)); + } catch (JsonProcessingException e) { + this.logger.error("Error when deserializing project " + + project_id, e); + } + } + + String user_res = "[]"; + if (RenkanSessionModeratorState.INSTANCE.getProjectsUsersList() + .containsKey(project_id)) { + try { + user_res = mapper + .writeValueAsString(RenkanSessionModeratorState.INSTANCE + .getProjectsUsersList().get(project_id)); + } catch (JsonProcessingException e) { + this.logger.error("Error when deserializing user list " + + project_id, e); + } + } + res.put("users_" + project_id, user_res); + } + + this.logger.debug("getLateJoinState res : " + res.toString()); + return res; + } } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/coweb/SpringConfigurer.java --- a/server/src/main/java/org/iri_research/renkan/coweb/SpringConfigurer.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/coweb/SpringConfigurer.java Wed Jan 15 18:36:27 2014 +0100 @@ -10,43 +10,40 @@ import org.springframework.stereotype.Component; @Component -//@Scope("prototype") -public class SpringConfigurer implements ApplicationContextAware -{ - - //private BayeuxServer bayeuxServer; - //private ServerAnnotationProcessor processor; - private final Logger logger = LoggerFactory.getLogger(SpringConfigurer.class); +// @Scope("prototype") +public class SpringConfigurer implements ApplicationContextAware { + + // private BayeuxServer bayeuxServer; + // private ServerAnnotationProcessor processor; + private final Logger logger = LoggerFactory + .getLogger(SpringConfigurer.class); private ApplicationContext context; - + private static volatile SpringConfigurer instance = null; - - private SpringConfigurer() - { - this.logger.debug("Building SpringConfigurer"); - } - - public static SpringConfigurer getInstance() { - if (instance == null) { - synchronized (SpringConfigurer.class) { - if(instance == null) { - instance = new SpringConfigurer(); - } - } - } - return instance; + + private SpringConfigurer() { + this.logger.debug("Building SpringConfigurer"); } + public static SpringConfigurer getInstance() { + if (instance == null) { + synchronized (SpringConfigurer.class) { + if (instance == null) { + instance = new SpringConfigurer(); + } + } + } + return instance; + } - - @Override - @Inject - public void setApplicationContext(ApplicationContext context) - throws BeansException { - this.context = context; - } - - public ApplicationContext getApplicationContext() { - return this.context; - } + @Override + @Inject + public void setApplicationContext(ApplicationContext context) + throws BeansException { + this.context = context; + } + + public ApplicationContext getApplicationContext() { + return this.context; + } } \ No newline at end of file diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/coweb/event/AbstractSyncEventManager.java --- a/server/src/main/java/org/iri_research/renkan/coweb/event/AbstractSyncEventManager.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/coweb/event/AbstractSyncEventManager.java Wed Jan 15 18:36:27 2014 +0100 @@ -1,7 +1,6 @@ package org.iri_research.renkan.coweb.event; import java.io.Serializable; -import java.util.Date; import java.util.List; import java.util.Map; @@ -15,6 +14,7 @@ import org.iri_research.renkan.repositories.IRenkanRepository; import org.iri_research.renkan.repositories.ProjectSyncsRepository; import org.iri_research.renkan.repositories.ProjectsRepository; +import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,194 +23,211 @@ import com.mongodb.DBObject; import com.mongodb.WriteResult; +public abstract class AbstractSyncEventManager, ID extends Serializable> + implements IPersistedSyncEventManager { -public abstract class AbstractSyncEventManager, ID extends Serializable> implements IPersistedSyncEventManager { + private final Logger logger = LoggerFactory + .getLogger(AbstractSyncEventManager.class); + + @Inject + private ProjectsRepository projectsRepository; + + @Inject + private ProjectSyncsRepository projectSyncsRepository; + + @Override + public ProjectsRepository getProjectsRepository() { + return this.projectsRepository; + } + + @Override + public abstract IRenkanRepository getObjectRepository(); + + @Override + public void dispatchEvent(String clientId, Map data) { - private final Logger logger = LoggerFactory.getLogger(AbstractSyncEventManager.class); - - @Inject - private ProjectsRepository projectsRepository; - - @Inject - private ProjectSyncsRepository projectSyncsRepository; - - @Override - public ProjectsRepository getProjectsRepository() { - return this.projectsRepository; - } - - @Override - public abstract IRenkanRepository getObjectRepository(); - - @Override - public void dispatchEvent(String clientId, Map data) { - - this.saveSyncEvent(data); + this.saveSyncEvent(data); + + String eventType = (String) data.get("type"); - String eventType = (String) data.get("type"); - - if("null".equalsIgnoreCase(eventType)) { - this.nullOperation(null, data); - } - else if ("update".equalsIgnoreCase(eventType)) { - this.update(clientId, data); - } - else if ("insert".equalsIgnoreCase(eventType)) { - this.insert(clientId, data); - } - else if("delete".equalsIgnoreCase(eventType)) { - this.delete(clientId, data); - } - else { - logger.warn(String.format("dispatchEvent : eventType unknown %s", eventType)); - } - } + if ("null".equalsIgnoreCase(eventType)) { + this.nullOperation(null, data); + } else if ("update".equalsIgnoreCase(eventType)) { + this.update(clientId, data); + } else if ("insert".equalsIgnoreCase(eventType)) { + this.insert(clientId, data); + } else if ("delete".equalsIgnoreCase(eventType)) { + this.delete(clientId, data); + } else { + logger.warn(String.format("dispatchEvent : eventType unknown %s", + eventType)); + } + } + + private void saveSyncEvent(Map data) { + + String project_id = null; + String user_id = null; + + @SuppressWarnings("unchecked") + Map values = (Map) data.get("value"); - private void saveSyncEvent(Map data) { - - String project_id = null; - String user_id = null; - - @SuppressWarnings("unchecked") - Map values = (Map) data.get("value"); - - if(values != null) { - project_id = (String) values.get("_project_id"); - } - - if (project_id == null || "".equals(project_id)) { - logger.warn("saveSyncEvent : project id is null. Can not save sync event"); - return; - } - - Project p = this.projectsRepository.findOne(project_id); - - if (p == null) { - logger.warn("saveSyncEvent : project not found. Can not save sync event"); - return; - } - - p.setUpdated(new Date()); - this.projectsRepository.save(p); - - user_id = (String) values.get("_user_id"); - - if (user_id == null) { - logger.warn("saveSyncEvent : No user id"); - } + if (values != null) { + project_id = (String) values.get("_project_id"); + } + + if (project_id == null || "".equals(project_id)) { + logger.warn("saveSyncEvent : project id is null. Can not save sync event"); + return; + } + + Project p = this.projectsRepository.findOne(project_id); + + if (p == null) { + logger.warn("saveSyncEvent : project not found. Can not save sync event"); + return; + } + + p.setUpdated(new DateTime()); + this.projectsRepository.save(p); + + user_id = (String) values.get("_user_id"); + + if (user_id == null) { + logger.warn("saveSyncEvent : No user id"); + } - try { - ProjectSync ps = this.projectSyncsRepository.getProjectSync(data.toString(), p, user_id); - this.projectSyncsRepository.save(ps); - } catch (RenkanException e) { - logger.warn("saveSyncEvent : Error when getting Projectr syn object",e); - } - - } + try { + ProjectSync ps = this.projectSyncsRepository.getProjectSync( + data.toString(), p, user_id); + this.projectSyncsRepository.save(ps); + } catch (RenkanException e) { + logger.warn( + "saveSyncEvent : Error when getting Projectr syn object", e); + } + + } + + protected abstract List getObjectList(Project project); - protected abstract List getObjectList(Project project); + @Override + public void update(String clientId, Map data) { + + this.logger.debug("AbstractSyncEventManager: update " + + this.getClass().getName()); + + @SuppressWarnings("unchecked") + Map values = (Map) data.get("value"); + String obj_id = (String) values.get("id"); + + this.logger.debug(String.format("update %s %s", this.getClass() + .getName(), obj_id)); + + DBCollection objCollection = this.getObjectRepository().getCollection(); + DBObject obj = objCollection.findOne(obj_id); - @Override - public void update(String clientId, Map data) { - - this.logger.debug("AbstractSyncEventManager: update " + this.getClass().getName()); - - @SuppressWarnings("unchecked") - Map values = (Map) data.get("value"); - String obj_id = (String) values.get("id"); - - this.logger.debug(String.format("update %s %s", this.getClass().getName(), obj_id)); - - DBCollection objCollection = this.getObjectRepository().getCollection(); - DBObject obj = objCollection.findOne(obj_id); - - if (null == obj) { - throw new CowebException("Object update: object not found", String.format("Object %s not found in %s", obj_id, objCollection.getName())); - } - - boolean obj_changed = false; - // update object - for (String fieldname : values.keySet()) { - if(!"id".equalsIgnoreCase(fieldname) && !fieldname.startsWith("_")) - { - Object new_value = values.get(fieldname); - Object old_value = obj.get(fieldname); - if((new_value == null && old_value != null) || (new_value != null && !new_value.equals(old_value))) { - obj.put(fieldname, new_value); - obj_changed = true; - } - } - } - - if(obj_changed) { - obj.put("_id", obj_id); - WriteResult res = this.getObjectRepository().getCollection().update(new BasicDBObject("_id", obj_id), obj, true, false); - - if(!res.getLastError().ok()) { - throw new CowebException(String.format("Error when writing object %s in %s", obj_id, objCollection.getName()), res.getLastError().getErrorMessage()); - } - } - } + if (null == obj) { + throw new CowebException("Object update: object not found", + String.format("Object %s not found in %s", obj_id, + objCollection.getName())); + } + + boolean obj_changed = false; + // update object + for (String fieldname : values.keySet()) { + if (!"id".equalsIgnoreCase(fieldname) && !fieldname.startsWith("_")) { + Object new_value = values.get(fieldname); + Object old_value = obj.get(fieldname); + if ((new_value == null && old_value != null) + || (new_value != null && !new_value.equals(old_value))) { + obj.put(fieldname, new_value); + obj_changed = true; + } + } + } + + if (obj_changed) { + obj.put("_id", obj_id); + WriteResult res = this.getObjectRepository().getCollection() + .update(new BasicDBObject("_id", obj_id), obj, true, false); - @Override - public abstract void insert(String clientId, Map data); + if (!res.getLastError().ok()) { + throw new CowebException(String.format( + "Error when writing object %s in %s", obj_id, + objCollection.getName()), res.getLastError() + .getErrorMessage()); + } + } + } + + @Override + public abstract void insert(String clientId, Map data); + + @Override + public void delete(String clientId, Map data) { + + @SuppressWarnings("unchecked") + Map values = (Map) data.get("value"); + String project_id = (String) values.get("_project_id"); + Project project = this.getProjectsRepository().findOne(project_id); + + if (null == project) { + throw new CowebException(this.getClass().getName() + + " delete: project not found", String.format( + "Project %s not found", project_id)); + } + + Integer position = (Integer) data.get("position"); - @Override - public void delete(String clientId, Map data) { - - @SuppressWarnings("unchecked") - Map values = (Map) data.get("value"); - String project_id = (String) values.get("_project_id"); - Project project = this.getProjectsRepository().findOne(project_id); - - if (null == project) { - throw new CowebException(this.getClass().getName() + " delete: project not found", String.format("Project %s not found", project_id)); - } + if (position == null || position < 0) { + throw new CowebException("object delete: bad delete position", + String.format("Bad position %s not found", + position == null ? "null" : position.toString())); + } + int index = position.intValue(); + + @SuppressWarnings("unchecked") + ID object_id = (ID) values.get("id"); + + this.logger.debug(String.format( + "delete object %s in pos %d for project %s", object_id, index, + project_id)); + + IRenkanModel currentObject = null; + + List objList = this.getObjectList(project); + + if (index < objList.size()) { + currentObject = objList.get(index); + } - Integer position = (Integer)data.get("position"); - - if(position == null || position < 0) { - throw new CowebException("object delete: bad delete position", String.format("Bad position %s not found", position==null?"null":position.toString())); - } - int index = position.intValue(); - - @SuppressWarnings("unchecked") - ID object_id = (ID) values.get("id"); - - this.logger.debug(String.format("delete object %s in pos %d for project %s", object_id, index, project_id)); - - IRenkanModel currentObject = null; - - List objList = this.getObjectList(project); - - if(index < objList.size()) { - currentObject = objList.get(index); - } - - if(currentObject == null || !object_id.equals(currentObject.getId())) { - index = -1; - this.logger.warn(String.format("delete object %s in pos %d for project %s not current object", object_id, index, project_id)); - for(int i=0;i data); - - + } + + @Override + public abstract void nullOperation(String clientId, Map data); + } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/coweb/event/EdgeSyncEventManager.java --- a/server/src/main/java/org/iri_research/renkan/coweb/event/EdgeSyncEventManager.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/coweb/event/EdgeSyncEventManager.java Wed Jan 15 18:36:27 2014 +0100 @@ -18,101 +18,107 @@ import org.slf4j.LoggerFactory; @Named -public class EdgeSyncEventManager extends AbstractSyncEventManager { +public class EdgeSyncEventManager extends + AbstractSyncEventManager { - private final Logger logger = LoggerFactory.getLogger(EdgeSyncEventManager.class); + private final Logger logger = LoggerFactory + .getLogger(EdgeSyncEventManager.class); - @Inject - private NodesRepository nodesRepository; + @Inject + private NodesRepository nodesRepository; - @Inject - private UsersRepository usersRepository; - - @Inject - private EdgesRepository edgesRepository; + @Inject + private UsersRepository usersRepository; + + @Inject + private EdgesRepository edgesRepository; - - public NodesRepository getNodesRepository() { - return nodesRepository; - } + public NodesRepository getNodesRepository() { + return nodesRepository; + } + + public UsersRepository getUsersRepository() { + return usersRepository; + } - public UsersRepository getUsersRepository() { - return usersRepository; - } + public EdgesRepository getEdgesRepository() { + return edgesRepository; + } + + @Override + public IRenkanRepository getObjectRepository() { + return this.getEdgesRepository(); + } + + @Override + public void insert(String clientId, Map data) { - public EdgesRepository getEdgesRepository() { - return edgesRepository; - } - - - @Override - public IRenkanRepository getObjectRepository() { - return this.getEdgesRepository(); - } - - - @Override - public void insert(String clientId, Map data) { - - // get project - this.logger.debug("EdgeSyncEventManager: insert Edge"); - - @SuppressWarnings("unchecked") - Map values = (Map) data.get("value"); - String project_id = (String) values.get("_project_id"); + // get project + this.logger.debug("EdgeSyncEventManager: insert Edge"); + + @SuppressWarnings("unchecked") + Map values = (Map) data.get("value"); + String project_id = (String) values.get("_project_id"); + + Project project = this.getProjectsRepository().findOne(project_id); + + if (null == project) { + throw new CowebException("Edge insert: project not found", + String.format("Project %s not found", project_id)); + } + + String creator_id = (String) values.get("created_by"); - Project project = this.getProjectsRepository().findOne(project_id); - - if (null == project) { - throw new CowebException("Edge insert: project not found", String.format("Project %s not found", project_id)); - } + String from_node_id = (String) values.get("from"); + Node from_node = this.getNodesRepository().findOne(from_node_id); + + if (null == from_node) { + throw new CowebException("Edge insert: from not found", + String.format("from %s not found", from_node_id)); + } + + String to_node_id = (String) values.get("to"); + Node to_node = this.getNodesRepository().findOne(to_node_id); + + if (null == to_node) { + throw new CowebException("Edge insert: to not found", + String.format("to %s not found", to_node_id)); + } + + String edge_id = (String) values.get("id"); + + Edge edge = new Edge(edge_id, (String) values.get("title"), + (String) values.get("description"), (String) values.get("uri"), + (String) values.get("color"), from_node, to_node, creator_id, + project_id); + + Integer position = (Integer) data.get("position"); - String creator_id = (String) values.get("created_by"); - - String from_node_id = (String)values.get("from"); - Node from_node = this.getNodesRepository().findOne(from_node_id); - - if(null == from_node) { - throw new CowebException("Edge insert: from not found", String.format("from %s not found", from_node_id)); - } - - String to_node_id = (String)values.get("to"); - Node to_node = this.getNodesRepository().findOne(to_node_id); - - if(null == to_node) { - throw new CowebException("Edge insert: to not found", String.format("to %s not found", to_node_id)); - } - - String edge_id = (String)values.get("id"); - - Edge edge = new Edge(edge_id, (String)values.get("title"), (String)values.get("description"), (String)values.get("uri"), (String)values.get("color"), from_node, to_node, creator_id, project_id); - - - Integer position = (Integer)data.get("position"); - - if(position == null || position < 0) { - throw new CowebException("Edge insert: bad insert position", String.format("Bad position %s not found", position==null?"null":position.toString())); - } - int index = position.intValue(); - List edges = project.getEdges(); - if(index > edges.size()) { - index = edges.size(); - } - edges.add(index,edge); + if (position == null || position < 0) { + throw new CowebException("Edge insert: bad insert position", + String.format("Bad position %s not found", + position == null ? "null" : position.toString())); + } + int index = position.intValue(); + List edges = project.getEdges(); + if (index > edges.size()) { + index = edges.size(); + } + edges.add(index, edge); - this.getEdgesRepository().save(edge); - this.getProjectsRepository().save(project); - - } - - @Override - public void nullOperation(String clientId, Map data) { - this.logger.debug("nullOperation: NOP"); - } + this.getEdgesRepository().save(edge); + this.getProjectsRepository().save(project); + + } - @Override - protected List getObjectList(Project project) { - return project.getEdges(); - } + @Override + public void nullOperation(String clientId, Map data) { + this.logger.debug("nullOperation: NOP"); + } + + @Override + protected List getObjectList(Project project) { + return project.getEdges(); + } } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/coweb/event/IPersistedSyncEventManager.java --- a/server/src/main/java/org/iri_research/renkan/coweb/event/IPersistedSyncEventManager.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/coweb/event/IPersistedSyncEventManager.java Wed Jan 15 18:36:27 2014 +0100 @@ -5,9 +5,11 @@ import org.iri_research.renkan.repositories.IRenkanRepository; import org.iri_research.renkan.repositories.ProjectsRepository; -public interface IPersistedSyncEventManager extends ISyncEventManager { - - public ProjectsRepository getProjectsRepository(); - public IRenkanRepository getObjectRepository(); +public interface IPersistedSyncEventManager extends + ISyncEventManager { + + public ProjectsRepository getProjectsRepository(); + + public IRenkanRepository getObjectRepository(); } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/coweb/event/ISyncEventManager.java --- a/server/src/main/java/org/iri_research/renkan/coweb/event/ISyncEventManager.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/coweb/event/ISyncEventManager.java Wed Jan 15 18:36:27 2014 +0100 @@ -4,13 +4,15 @@ import java.util.Map; public interface ISyncEventManager { - - public void dispatchEvent(String clientId, Map data); + + public void dispatchEvent(String clientId, Map data); + + public void update(String clientId, Map data); - public void update(String clientId, Map data); - public void insert(String clientId, Map data); - public void delete(String clientId, Map data); - public void nullOperation(String clientId, Map data); - + public void insert(String clientId, Map data); + + public void delete(String clientId, Map data); + + public void nullOperation(String clientId, Map data); } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/coweb/event/NodeSyncEventManager.java --- a/server/src/main/java/org/iri_research/renkan/coweb/event/NodeSyncEventManager.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/coweb/event/NodeSyncEventManager.java Wed Jan 15 18:36:27 2014 +0100 @@ -17,87 +17,96 @@ import org.springframework.data.mongodb.core.geo.Point; @Named -public class NodeSyncEventManager extends AbstractSyncEventManager { +public class NodeSyncEventManager extends + AbstractSyncEventManager { - private final Logger logger = LoggerFactory.getLogger(NodeSyncEventManager.class); + private final Logger logger = LoggerFactory + .getLogger(NodeSyncEventManager.class); + + @Inject + private NodesRepository nodesRepository; - @Inject - private NodesRepository nodesRepository; + @Inject + private UsersRepository usersRepository; - @Inject - private UsersRepository usersRepository; + public NodesRepository getNodesRepository() { + return nodesRepository; + } + + @Override + public IRenkanRepository getObjectRepository() { + return this.getNodesRepository(); + } - - public NodesRepository getNodesRepository() { - return nodesRepository; - } - - @Override - public IRenkanRepository getObjectRepository() { - return this.getNodesRepository(); - } - - public UsersRepository getUsersRepository() { - return this.usersRepository; - } + public UsersRepository getUsersRepository() { + return this.usersRepository; + } + + @Override + public void insert(String clientId, Map data) { + + // get project + this.logger.debug("NodeSyncEventManager: insert Node"); - - @Override - public void insert(String clientId, Map data) { - - // get project - this.logger.debug("NodeSyncEventManager: insert Node"); - - @SuppressWarnings("unchecked") - Map values = (Map) data.get("value"); - String project_id = (String) values.get("_project_id"); + @SuppressWarnings("unchecked") + Map values = (Map) data.get("value"); + String project_id = (String) values.get("_project_id"); + + Project project = this.getProjectsRepository().findOne(project_id); - Project project = this.getProjectsRepository().findOne(project_id); - - if (null == project) { - throw new CowebException("node insert: project not found", String.format("Project %s not found", project_id)); - } + if (null == project) { + throw new CowebException("node insert: project not found", + String.format("Project %s not found", project_id)); + } + + String creator_id = (String) values.get("created_by"); - String creator_id = (String) values.get("created_by"); - - @SuppressWarnings("unchecked") - Map positionValues = (Map) values.get("position"); - - Point nodePosition = new Point(((Number)positionValues.get("x")).doubleValue(), ((Number)positionValues.get("y")).doubleValue()); - - String image = (String)values.get("image"); - - String node_id = (String)values.get("id"); - - Integer size = (Integer)values.get("size"); - - Node node = new Node(node_id, (String)values.get("title"), (String)values.get("description"), (String)values.get("uri"), (String)values.get("color"), creator_id, nodePosition, image, size, project_id); - - Integer position = (Integer)data.get("position"); - - if(position == null || position < 0) { - throw new CowebException("node insert: bad insert position", String.format("Bad position %s not found", position==null?"null":position.toString())); - } - int index = position.intValue(); - List nodes = project.getNodes(); - if(index > nodes.size()) { - index = nodes.size(); - } - nodes.add(index,node); + @SuppressWarnings("unchecked") + Map positionValues = (Map) values + .get("position"); + + Point nodePosition = new Point( + ((Number) positionValues.get("x")).doubleValue(), + ((Number) positionValues.get("y")).doubleValue()); + + String image = (String) values.get("image"); + + String node_id = (String) values.get("id"); + + Integer size = (Integer) values.get("size"); + + Node node = new Node(node_id, (String) values.get("title"), + (String) values.get("description"), (String) values.get("uri"), + (String) values.get("color"), creator_id, nodePosition, image, + size, project_id); + + Integer position = (Integer) data.get("position"); - this.getNodesRepository().save(node); - this.getProjectsRepository().save(project); - - } - - @Override - public void nullOperation(String clientId, Map data) { - this.logger.debug("nullOperation: NOP"); - } + if (position == null || position < 0) { + throw new CowebException("node insert: bad insert position", + String.format("Bad position %s not found", + position == null ? "null" : position.toString())); + } + int index = position.intValue(); + List nodes = project.getNodes(); + if (index > nodes.size()) { + index = nodes.size(); + } + nodes.add(index, node); - @Override - protected List getObjectList(Project project) { - return project.getNodes(); - } + this.getNodesRepository().save(node); + this.getProjectsRepository().save(project); + + } + + @Override + public void nullOperation(String clientId, Map data) { + this.logger.debug("nullOperation: NOP"); + } + + @Override + protected List getObjectList(Project project) { + return project.getNodes(); + } } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/coweb/event/ProjectSyncEventManager.java --- a/server/src/main/java/org/iri_research/renkan/coweb/event/ProjectSyncEventManager.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/coweb/event/ProjectSyncEventManager.java Wed Jan 15 18:36:27 2014 +0100 @@ -15,50 +15,63 @@ /** * @author ymh - * + * */ @Named -public class ProjectSyncEventManager extends AbstractSyncEventManager { +public class ProjectSyncEventManager extends + AbstractSyncEventManager { + + private final Logger logger = LoggerFactory + .getLogger(ProjectSyncEventManager.class); + + @Override + public IRenkanRepository getObjectRepository() { + return this.getProjectsRepository(); + } - private final Logger logger = LoggerFactory.getLogger(ProjectSyncEventManager.class); - - @Override - public IRenkanRepository getObjectRepository() { - return this.getProjectsRepository(); - } - - /* (non-Javadoc) - * @see org.iri_research.renkan.coweb.event.AbstractSyncEventManager#insert(java.util.Map) - */ - @Override - public void insert(String clientId, Map data) { - this.logger.debug("Insert called, do nothing"); - // do nothing - } + /* + * (non-Javadoc) + * + * @see + * org.iri_research.renkan.coweb.event.AbstractSyncEventManager#insert(java + * .util.Map) + */ + @Override + public void insert(String clientId, Map data) { + this.logger.debug("Insert called, do nothing"); + // do nothing + } - /* (non-Javadoc) - * @see org.iri_research.renkan.coweb.event.AbstractSyncEventManager#delete(java.util.Map) - */ - @Override - public void delete(String clientId, Map data) { - this.logger.debug("Delete called, do nothing"); - // do nothing - } + /* + * (non-Javadoc) + * + * @see + * org.iri_research.renkan.coweb.event.AbstractSyncEventManager#delete(java + * .util.Map) + */ + @Override + public void delete(String clientId, Map data) { + this.logger.debug("Delete called, do nothing"); + // do nothing + } - /* (non-Javadoc) - * @see org.iri_research.renkan.coweb.event.AbstractSyncEventManager#nullOperation(java.util.Map) - */ - @Override - public void nullOperation(String clientId, Map data) { - this.logger.debug("Null called, do nothing"); - // do nothing - } + /* + * (non-Javadoc) + * + * @see + * org.iri_research.renkan.coweb.event.AbstractSyncEventManager#nullOperation + * (java.util.Map) + */ + @Override + public void nullOperation(String clientId, Map data) { + this.logger.debug("Null called, do nothing"); + // do nothing + } - @Override - protected List getObjectList(Project project) { - this.logger.error("Get object list called error"); - throw new UnsupportedOperationException("Get object list called error"); - } - + @Override + protected List getObjectList(Project project) { + this.logger.error("Get object list called error"); + throw new UnsupportedOperationException("Get object list called error"); + } } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/coweb/event/RosterSyncEventManager.java --- a/server/src/main/java/org/iri_research/renkan/coweb/event/RosterSyncEventManager.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/coweb/event/RosterSyncEventManager.java Wed Jan 15 18:36:27 2014 +0100 @@ -12,185 +12,196 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +@Named +public class RosterSyncEventManager implements + ISyncEventManager { -@Named -public class RosterSyncEventManager implements ISyncEventManager { + private final Logger logger = LoggerFactory + .getLogger(RosterSyncEventManager.class); - private final Logger logger = LoggerFactory.getLogger(RosterSyncEventManager.class); - + @Override + public void insert(String clientId, Map data) { + logger.debug("RosterUserSyncEventManager.insert " + data.toString()); + + @SuppressWarnings("unchecked") + Map values = (Map) data.get("value"); + String projectId = (String) values.get("_project_id"); + + List usersList = null; - @Override - public void insert(String clientId, Map data) { - logger.debug("RosterUserSyncEventManager.insert " + data.toString()); - - @SuppressWarnings("unchecked") - Map values = (Map) data.get("value"); - String projectId = (String) values.get("_project_id"); + if (RenkanSessionModeratorState.INSTANCE.getProjectsUsersList() + .containsKey(projectId)) { + usersList = RenkanSessionModeratorState.INSTANCE + .getProjectsUsersList().get(projectId); + } + if (usersList == null) { + usersList = new ArrayList(); + RenkanSessionModeratorState.INSTANCE.getProjectsUsersList().put( + projectId, usersList); + } + + String id = (String) values.get("id"); - List usersList = null; - - if(RenkanSessionModeratorState.INSTANCE.getProjectsUsersList().containsKey(projectId)) { - usersList = RenkanSessionModeratorState.INSTANCE.getProjectsUsersList().get(projectId); - } - if(usersList == null) { - usersList = new ArrayList(); - RenkanSessionModeratorState.INSTANCE.getProjectsUsersList().put(projectId, usersList); - } - - String id = (String)values.get("id"); + RosterUser user = null; + + for (RosterUser rosterUser : usersList) { + if (rosterUser.getId().equals(id)) { + user = rosterUser; + break; + } + } + if (user != null) { + this.update(clientId, data); + return; + } - RosterUser user = null; - - for (RosterUser rosterUser : usersList) { - if(rosterUser.getId().equals(id)) { - user = rosterUser; - break; - } - } - if(user != null) { - this.update(clientId, data); - return; - } - - String title = (String)values.get("title"); - String description = (String)values.get("description"); - String uri = (String)values.get("uri"); - String color = (String)values.get("color"); - Long site_id = (Long)values.get("site_id"); - - user = new RosterUser(id, title, description, uri, color, projectId, site_id, clientId); - - Integer position = (Integer)data.get("position"); - if(position == null) { - position = new Integer(0); - } - - usersList.add(position.intValue(), user); - - logger.debug("RosterUserSyncEventManager.insert in " + projectId + " : " + RenkanSessionModeratorState.INSTANCE.getProjectsActivationMap().toString()); - - } + String title = (String) values.get("title"); + String description = (String) values.get("description"); + String uri = (String) values.get("uri"); + String color = (String) values.get("color"); + Long site_id = (Long) values.get("site_id"); + + user = new RosterUser(id, title, description, uri, color, projectId, + site_id, clientId); + + Integer position = (Integer) data.get("position"); + if (position == null) { + position = new Integer(0); + } + + usersList.add(position.intValue(), user); + + logger.debug("RosterUserSyncEventManager.insert in " + + projectId + + " : " + + RenkanSessionModeratorState.INSTANCE + .getProjectsActivationMap().toString()); + + } - @Override - public void nullOperation(String clientId, Map data) { - // do nothing - return; - } + @Override + public void nullOperation(String clientId, Map data) { + // do nothing + return; + } - @Override - public void update(String clientId, Map data) { - logger.debug("RosterUserSyncEventManager.update " + data.toString()); + @Override + public void update(String clientId, Map data) { + logger.debug("RosterUserSyncEventManager.update " + data.toString()); + + @SuppressWarnings("unchecked") + Map values = (Map) data.get("value"); + String projectId = (String) values.get("_project_id"); - @SuppressWarnings("unchecked") - Map values = (Map) data.get("value"); - String projectId = (String) values.get("_project_id"); + List usersList = null; - List usersList = null; - - if(RenkanSessionModeratorState.INSTANCE.getProjectsUsersList().containsKey(projectId)) { - usersList = RenkanSessionModeratorState.INSTANCE.getProjectsUsersList().get(projectId); - } - - if(usersList == null) { - logger.debug("RosterUserSyncEventManager.update : null user list"); - return; - } - - String id = (String)values.get("id"); + if (RenkanSessionModeratorState.INSTANCE.getProjectsUsersList() + .containsKey(projectId)) { + usersList = RenkanSessionModeratorState.INSTANCE + .getProjectsUsersList().get(projectId); + } + + if (usersList == null) { + logger.debug("RosterUserSyncEventManager.update : null user list"); + return; + } + + String id = (String) values.get("id"); - RosterUser user = null; - - for (RosterUser rosterUser : usersList) { - if(rosterUser.getId().equals(id)) { - user = rosterUser; - break; - } - } - - if(user == null) { - logger.debug("RosterUserSyncEventManager.update : user not found in list"); - return; - } - - String title = (String)values.get("title"); - String description = (String)values.get("description"); - String uri = (String)values.get("uri"); - String color = (String)values.get("color"); - - if(title != null) { - user.setTitle(title); - } - if(description != null) { - user.setDescription(description); - } - if(uri != null) { - user.setUri(uri); - } - if(color != null) { - user.setColor(color); - } - - return; - - } + RosterUser user = null; + + for (RosterUser rosterUser : usersList) { + if (rosterUser.getId().equals(id)) { + user = rosterUser; + break; + } + } + + if (user == null) { + logger.debug("RosterUserSyncEventManager.update : user not found in list"); + return; + } + + String title = (String) values.get("title"); + String description = (String) values.get("description"); + String uri = (String) values.get("uri"); + String color = (String) values.get("color"); - @Override - public void delete(String clientId, Map data) { - logger.debug("RosterUserSyncEventManager.delete " + data.toString()); - - @SuppressWarnings("unchecked") - Map values = (Map) data.get("value"); - String projectId = (String) values.get("_project_id"); + if (title != null) { + user.setTitle(title); + } + if (description != null) { + user.setDescription(description); + } + if (uri != null) { + user.setUri(uri); + } + if (color != null) { + user.setColor(color); + } + + return; + + } + + @Override + public void delete(String clientId, Map data) { + logger.debug("RosterUserSyncEventManager.delete " + data.toString()); + + @SuppressWarnings("unchecked") + Map values = (Map) data.get("value"); + String projectId = (String) values.get("_project_id"); + + List usersList = null; - List usersList = null; - - if(RenkanSessionModeratorState.INSTANCE.getProjectsUsersList().containsKey(projectId)) { - usersList = RenkanSessionModeratorState.INSTANCE.getProjectsUsersList().get(projectId); - } - - if(usersList == null) { - logger.debug("RosterUserSyncEventManager.delete : null user list"); - return; - } - - Integer position = (Integer)data.get("position"); - - if(position == null || position < 0) { - throw new CowebException("object delete: bad delete position", String.format("Bad position %s not found", position==null?"null":position.toString())); - } - int index = position.intValue(); - - usersList.remove(index); - - if(usersList.isEmpty()) { - RenkanSessionModeratorState.INSTANCE.getProjectsUsersList().remove(projectId); - } - - return; - - } - - @Override - public void dispatchEvent(String clientId, Map data) { - - String eventType = (String) data.get("type"); - - if("null".equalsIgnoreCase(eventType)) { - this.nullOperation(clientId, data); - } - else if ("update".equalsIgnoreCase(eventType)) { - this.update(clientId, data); - } - else if ("insert".equalsIgnoreCase(eventType)) { - this.insert(clientId, data); - } - else if("delete".equalsIgnoreCase(eventType)) { - this.delete(clientId, data); - } - else { - logger.warn(String.format("dispatchEvent : eventType unknown %s", eventType)); - } - } + if (RenkanSessionModeratorState.INSTANCE.getProjectsUsersList() + .containsKey(projectId)) { + usersList = RenkanSessionModeratorState.INSTANCE + .getProjectsUsersList().get(projectId); + } + + if (usersList == null) { + logger.debug("RosterUserSyncEventManager.delete : null user list"); + return; + } + + Integer position = (Integer) data.get("position"); + + if (position == null || position < 0) { + throw new CowebException("object delete: bad delete position", + String.format("Bad position %s not found", + position == null ? "null" : position.toString())); + } + int index = position.intValue(); + + usersList.remove(index); + if (usersList.isEmpty()) { + RenkanSessionModeratorState.INSTANCE.getProjectsUsersList().remove( + projectId); + } + + return; + + } + + @Override + public void dispatchEvent(String clientId, Map data) { + + String eventType = (String) data.get("type"); + + if ("null".equalsIgnoreCase(eventType)) { + this.nullOperation(clientId, data); + } else if ("update".equalsIgnoreCase(eventType)) { + this.update(clientId, data); + } else if ("insert".equalsIgnoreCase(eventType)) { + this.insert(clientId, data); + } else if ("delete".equalsIgnoreCase(eventType)) { + this.delete(clientId, data); + } else { + logger.warn(String.format("dispatchEvent : eventType unknown %s", + eventType)); + } + } } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/coweb/event/UserSyncEventManager.java --- a/server/src/main/java/org/iri_research/renkan/coweb/event/UserSyncEventManager.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/coweb/event/UserSyncEventManager.java Wed Jan 15 18:36:27 2014 +0100 @@ -1,5 +1,6 @@ package org.iri_research.renkan.coweb.event; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -15,74 +16,83 @@ import org.slf4j.LoggerFactory; @Named -public class UserSyncEventManager extends AbstractSyncEventManager { +public class UserSyncEventManager extends + AbstractSyncEventManager { + + private final Logger logger = LoggerFactory + .getLogger(UserSyncEventManager.class); - private final Logger logger = LoggerFactory.getLogger(UserSyncEventManager.class); - - private final static String DEFAULT_COLOR = "#000080"; + private final static String DEFAULT_COLOR = "#000080"; + + @Inject + private UsersRepository usersRepository; + + public UsersRepository getUsersRepository() { + return this.usersRepository; + } - @Inject - private UsersRepository usersRepository; - - public UsersRepository getUsersRepository() { - return this.usersRepository; - } - - @Override - public IRenkanRepository getObjectRepository() { - return this.getUsersRepository(); - } + @Override + public IRenkanRepository getObjectRepository() { + return this.getUsersRepository(); + } + + @Override + public void insert(String clientId, Map data) { + + // get project + this.logger.debug("UserSyncEventManager: insert User"); + @SuppressWarnings("unchecked") + Map values = (Map) data.get("value"); + String project_id = (String) values.get("_project_id"); - @Override - public void insert(String clientId, Map data) { - - // get project - this.logger.debug("UserSyncEventManager: insert User"); - - @SuppressWarnings("unchecked") - Map values = (Map) data.get("value"); - String project_id = (String) values.get("_project_id"); + Project project = this.getProjectsRepository().findOne(project_id); + + if (null == project) { + throw new CowebException("user insert: project not found", + String.format("Project %s not found", project_id)); + } - Project project = this.getProjectsRepository().findOne(project_id); - - if (null == project) { - throw new CowebException("user insert: project not found", String.format("Project %s not found", project_id)); - } - - String user_id = (String)values.get("id"); - String color = (String)values.get("color"); - if(color == null || color.length() == 0) { - color = UserSyncEventManager.DEFAULT_COLOR; - } - - User user = new User(user_id, (String)values.get("title"), (String)values.get("description"), (String)values.get("uri"), color, project_id); - - Integer position = (Integer)data.get("position"); - - if(position == null || position < 0) { - throw new CowebException("node insert: bad insert position", String.format("Bad position %s not found", position==null?"null":position.toString())); - } - int index = position.intValue(); - List users = project.getUsers(); - if(index > users.size()) { - index = users.size(); - } - users.add(index,user); + String user_id = (String) values.get("id"); + String color = (String) values.get("color"); + if (color == null || color.length() == 0) { + color = UserSyncEventManager.DEFAULT_COLOR; + } + + User user = new User(user_id, (String) values.get("title"), + (String) values.get("description"), (String) values.get("uri"), + color); + + Integer position = (Integer) data.get("position"); - this.getUsersRepository().save(user); - this.getProjectsRepository().save(project); - - } + if (position == null || position < 0) { + throw new CowebException("node insert: bad insert position", + String.format("Bad position %s not found", + position == null ? "null" : position.toString())); + } + int index = position.intValue(); + // TODO: correct this. done that to compile + List users = new ArrayList();// project.getUsers(); + if (index > users.size()) { + index = users.size(); + } + users.add(index, user); - @Override - public void nullOperation(String clientId, Map data) { - this.logger.debug("nullOperation: NOP"); - } + this.getUsersRepository().save(user); + this.getProjectsRepository().save(project); + + } - @Override - protected List getObjectList(Project project) { - return project.getUsers(); - } + @Override + public void nullOperation(String clientId, Map data) { + this.logger.debug("nullOperation: NOP"); + } + + @Override + protected List getObjectList(Project project) { + // TODO: correct this, this is wrong, just put here to cpmpile + return null; + // return project.getUsers(); + } } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/forms/GroupForm.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/java/org/iri_research/renkan/forms/GroupForm.java Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,84 @@ +package org.iri_research.renkan.forms; + +import java.util.HashSet; +import java.util.Set; + +import org.iri_research.renkan.Constants; +import org.iri_research.renkan.models.Group; +import org.iri_research.renkan.repositories.GroupsRepository; +import org.iri_research.renkan.repositories.IRenkanRepository; +import org.springframework.beans.factory.annotation.Autowired; + +public class GroupForm extends RenkanForm { + + private String avatar; + private Set users; + + private GroupsRepository groupsRepository; + + + public GroupForm() { + super(); + } + + public GroupForm(Group model) { + super(model); + if (model != null) { + this.avatar = model.getAvatar(); + this.setUsers(new HashSet<>(model.getUsers())); + if(model.getUsers() != null) { + this.getUsers().addAll(model.getUsers()); + } + } + } + + public String getAvatar() { + return avatar; + } + + @Override + protected Group getModelInstance() { + return new Group(); + } + + @Override + protected IRenkanRepository getRepository() { + return this.groupsRepository; + } + + public GroupsRepository getGroupsRepository() { + return groupsRepository; + } + + + @Override + protected void saveToModel() { + if (this.getId() == null || this.getId().length() == 0) { + this.model.setId(Constants.UUID_GENERATOR.generate().toString()); + } + this.model.setAvatar(this.avatar); + if(this.getUsers() != null) { + this.groupsRepository.setUsersList(model, this.getUsers()); + } + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + + @Autowired + public void setGroupsRepository(GroupsRepository groupsRepository) { + this.groupsRepository = groupsRepository; + } + + public Set getUsers() { + return users; + } + + public void setUsers(Set users) { + this.users = users; + } + + +} diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/forms/GroupFormValidator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/java/org/iri_research/renkan/forms/GroupFormValidator.java Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,27 @@ +package org.iri_research.renkan.forms; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.validation.Errors; +import org.springframework.validation.ValidationUtils; +import org.springframework.validation.Validator; + +@Component +public class GroupFormValidator implements Validator { + + @SuppressWarnings("unused") + private Logger logger = LoggerFactory.getLogger(GroupFormValidator.class); + + @Override + public boolean supports(Class clazz) { + return GroupForm.class.equals(clazz); + } + + @Override + public void validate(Object target, Errors errors) { + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "title", + "renkan.error.name.empty"); + } + +} diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/forms/RenkanForm.java --- a/server/src/main/java/org/iri_research/renkan/forms/RenkanForm.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/forms/RenkanForm.java Wed Jan 15 18:36:27 2014 +0100 @@ -6,99 +6,111 @@ import org.iri_research.renkan.models.IRenkanModel; import org.iri_research.renkan.repositories.IRenkanRepository; -public abstract class RenkanForm > { - - protected RM model; - - private ID id; - private String title; - private String description; - private String uri; - private String color; - - protected abstract void saveToModel(); - protected abstract IRenkanRepository getRepository(); - protected abstract RM getModelInstance(); - - public RenkanForm() {} - - public RenkanForm(RM model) { - this.model = model; - this.id = model.getId(); - this.title = model.getTitle(); - this.description = model.getDescription(); - this.color = model.getColor(); - this.uri = model.getUri(); - } - - public ID getId() { - return id; - } - public void setId(ID id) { - this.id = id; - } - public String getTitle() { - return title; - } - public void setTitle(String title) { - this.title = title; - } - public String getDescription() { - return description; - } - public void setDescription(String description) { - this.description = description; - } - public String getUri() { - return uri; - } - public void setUri(String uri) { - this.uri = uri; - } - public String getColor() { - return color; - } - public void setColor(String color) { - this.color = color; - } - - public void setModel(RM model) { - this.model = model; - } - - private void saveToRenkanModel() { - - this.model.setTitle(title); - this.model.setDescription(description); - this.model.setColor(color); - this.model.setUri(uri); - } - - - public RM save() throws RenkanException { +public abstract class RenkanForm> { + + protected RM model; + + private ID id; + private String title; + private String description; + private String uri; + private String color; + + protected abstract void saveToModel(); + + protected abstract IRenkanRepository getRepository(); + + protected abstract RM getModelInstance(); + + public RenkanForm() { + } + + public RenkanForm(RM model) { + if (model == null) { + return; + } + this.model = model; + this.id = model.getId(); + this.title = model.getTitle(); + this.description = model.getDescription(); + this.color = model.getColor(); + this.uri = model.getUri(); + } + + public ID getId() { + return id; + } + + public void setId(ID id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } - if(this.model == null) { - - if(this.getId() != null) { - this.model = this.getRepository().findOne(this.getId()); - if(this.model == null) { - throw new RenkanException("Model id " + this.getId().toString() + " not found"); - } - } - else { - this.model = this.getModelInstance(); - } - } - - this.saveToRenkanModel(); - this.saveToModel(); - - this.model = this.getRepository().save(this.model); - - return this.model; - - } - - + public void setDescription(String description) { + this.description = description; + } + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } + + public void setModel(RM model) { + this.model = model; + } + + private void saveToRenkanModel() { + + this.model.setTitle(title); + this.model.setDescription(description); + this.model.setColor(color); + this.model.setUri(uri); + } + + public RM save() throws RenkanException { + + if (this.model == null) { + + if (this.getId() != null) { + this.model = this.getRepository().findOne(this.getId()); + if (this.model == null) { + throw new RenkanException("Model id " + + this.getId().toString() + " not found"); + } + } else { + this.model = this.getModelInstance(); + } + } + + this.saveToRenkanModel(); + this.saveToModel(); + + this.model = this.getRepository().save(this.model); + + return this.model; + + } } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/forms/SpaceForm.java --- a/server/src/main/java/org/iri_research/renkan/forms/SpaceForm.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/forms/SpaceForm.java Wed Jan 15 18:36:27 2014 +0100 @@ -1,69 +1,66 @@ package org.iri_research.renkan.forms; -import java.util.Date; - import org.iri_research.renkan.Constants; import org.iri_research.renkan.models.Space; import org.iri_research.renkan.repositories.IRenkanRepository; import org.iri_research.renkan.repositories.SpacesRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; +import org.joda.time.DateTime; -@Component public class SpaceForm extends RenkanForm { - - @Autowired - private SpacesRepository spacesRepository; - - public SpaceForm() { - super(); - } - - public SpaceForm(Space model) { - super(model); - this.binConfig = model.getBinConfig(); - this.image = model.getImage(); - } - - private String binConfig; - private String image; + + private SpacesRepository spacesRepository; + + public SpaceForm() { + super(); + } + + public SpaceForm(Space model) { + super(model); + this.binConfig = model.getBinConfig(); + this.image = model.getImage(); + } + + private String binConfig; + private String image; + + public String getBinConfig() { + return binConfig; + } + + public void setBinConfig(String binConfig) { + this.binConfig = binConfig; + } - public String getBinConfig() { - return binConfig; - } - public void setBinConfig(String binConfig) { - this.binConfig = binConfig; - } - public String getImage() { - return image; - } - public void setImage(String image) { - this.image = image; - } + public String getImage() { + return image; + } + + public void setImage(String image) { + this.image = image; + } - @Override - protected void saveToModel() { - if(this.getId() == null || this.getId().length() == 0) { - this.model.setId(Constants.UUID_GENERATOR.generate().toString()); - this.model.setCreated(new Date()); - } - this.model.setBinConfig(binConfig); - this.model.setImage(image); - } + @Override + protected void saveToModel() { + if (this.getId() == null || this.getId().length() == 0) { + this.model.setId(Constants.UUID_GENERATOR.generate().toString()); + this.model.setCreated(new DateTime()); + } + this.model.setBinConfig(binConfig); + this.model.setImage(image); + } - @Override - protected IRenkanRepository getRepository() { - return this.spacesRepository; - } + @Override + protected IRenkanRepository getRepository() { + return this.spacesRepository; + } - @Override - protected Space getModelInstance() { - return new Space(); - } + @Override + protected Space getModelInstance() { + return new Space(); + } - @Autowired - public void setSpacesRepository(SpacesRepository spacesRepository) { - this.spacesRepository = spacesRepository; - } - + public void setSpacesRepository(SpacesRepository spacesRepository) { + this.spacesRepository = spacesRepository; + } + } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/forms/SpaceFormValidator.java --- a/server/src/main/java/org/iri_research/renkan/forms/SpaceFormValidator.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/forms/SpaceFormValidator.java Wed Jan 15 18:36:27 2014 +0100 @@ -11,38 +11,46 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.joda.JodaModule; @Component public class SpaceFormValidator implements Validator { - - private Logger logger = LoggerFactory.getLogger(SpaceFormValidator.class); + + private Logger logger = LoggerFactory.getLogger(SpaceFormValidator.class); - @Override - public boolean supports(Class clazz) { - return SpaceForm.class.equals(clazz); - } + @Override + public boolean supports(Class clazz) { + return SpaceForm.class.equals(clazz); + } - @Override - public void validate(Object target, Errors errors) { - SpaceForm space = (SpaceForm)target; + @Override + public void validate(Object target, Errors errors) { + SpaceForm space = (SpaceForm) target; + + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "title", + "renkan.error.title.empty"); - ValidationUtils.rejectIfEmptyOrWhitespace(errors, "title", "renkan.error.title.empty"); - - if(space.getBinConfig() != null && space.getBinConfig().length()>0) { - boolean valid = false; - ObjectMapper mapper = new ObjectMapper(); - try { - mapper.readTree(space.getBinConfig()); - valid = true; - } catch (JsonProcessingException e) { - logger.debug("SpaceValidator JsonProcessingException error validating bin config", e); - } catch (IOException e) { - logger.debug("SpaceValidator IOException error validating bin config", e); - } - if(!valid) { - errors.rejectValue("binConfig", "renkan.error.bin_config.json"); - } - } - } + if (space.getBinConfig() != null && space.getBinConfig().length() > 0) { + boolean valid = false; + ObjectMapper mapper = new ObjectMapper(); + mapper.registerModule(new JodaModule()); + + try { + mapper.readTree(space.getBinConfig()); + valid = true; + } catch (JsonProcessingException e) { + logger.debug( + "SpaceValidator JsonProcessingException error validating bin config", + e); + } catch (IOException e) { + logger.debug( + "SpaceValidator IOException error validating bin config", + e); + } + if (!valid) { + errors.rejectValue("binConfig", "renkan.error.bin_config.json"); + } + } + } } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/forms/UserForm.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/java/org/iri_research/renkan/forms/UserForm.java Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,183 @@ +package org.iri_research.renkan.forms; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.iri_research.renkan.Constants; +import org.iri_research.renkan.models.User; +import org.iri_research.renkan.repositories.IRenkanRepository; +import org.iri_research.renkan.repositories.UsersRepository; +import org.joda.time.LocalDate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.format.annotation.DateTimeFormat.ISO; +import org.springframework.security.crypto.password.PasswordEncoder; + +public class UserForm extends RenkanForm { + + private String avatar; + + @DateTimeFormat(iso = ISO.DATE) + private LocalDate credentialsExpirationDate; + @DateTimeFormat(iso = ISO.DATE) + private LocalDate expirationDate; + + private String email; + + private boolean enabled; + private boolean locked; + private String password; + private String passwordConfirm; + private Set groups; + private List userAuthorities; + + private UsersRepository usersRepository; + + + private PasswordEncoder passwordEncoder; + + public void setPasswordEncoder(PasswordEncoder passwordEncoder) { + this.passwordEncoder = passwordEncoder; + } + + public UserForm() { + super(); + } + + public UserForm(User model) { + super(model); + if (model != null) { + this.avatar = model.getAvatar(); + this.credentialsExpirationDate = model.getCredentialsExpirationDate(); + this.email = model.getEmail(); + this.expirationDate = model.getExpirationDate(); + this.enabled = model.isEnabled(); + this.locked = model.isLocked(); + this.userAuthorities = model.getUserAuthorities()!=null?new ArrayList(model.getUserAuthorities()):new ArrayList(); + this.setGroups(new HashSet<>(model.getGroups())); + } + } + + public String getAvatar() { + return avatar; + } + + public LocalDate getCredentialsExpirationDate() { + return credentialsExpirationDate; + } + + public String getEmail() { + return email; + } + + public LocalDate getExpirationDate() { + return expirationDate; + } + + @Override + protected User getModelInstance() { + return new User(); + } + + public String getPassword() { + return password; + } + + public String getPasswordConfirm() { + return passwordConfirm; + } + + @Override + protected IRenkanRepository getRepository() { + return this.usersRepository; + } + + public UsersRepository getUsersRepository() { + return usersRepository; + } + + public boolean isEnabled() { + return enabled; + } + + public boolean isLocked() { + return locked; + } + + @Override + protected void saveToModel() { + if (this.getId() == null || this.getId().length() == 0) { + this.model.setId(Constants.UUID_GENERATOR.generate().toString()); + } + this.model.setAvatar(this.avatar); + this.model.setEmail(this.email); + this.model.setCredentialsExpirationDate(this.credentialsExpirationDate); + this.model.setExpirationDate(this.expirationDate); + this.model.setEnabled(this.enabled); + this.model.setLocked(this.locked); + this.model.setUserAuthorities((this.userAuthorities!=null && !this.userAuthorities.isEmpty())?new ArrayList(this.userAuthorities):null); + if(this.getGroups() != null) { + this.usersRepository.setGroupsList(this.model, this.getGroups()); + } + if(this.password != null && this.password.length() > 0) { + this.model.setPassword(this.passwordEncoder.encode(this.password)); + } + + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public void setCredentialsExpirationDate(LocalDate credentialsExpirationDate) { + this.credentialsExpirationDate = credentialsExpirationDate; + } + + public void setEmail(String email) { + this.email = email; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public void setExpirationDate(LocalDate expirationDate) { + this.expirationDate = expirationDate; + } + + public void setLocked(boolean locked) { + this.locked = locked; + } + + public void setPassword(String password) { + this.password = password; + } + + public void setPasswordConfirm(String passwordConfirm) { + this.passwordConfirm = passwordConfirm; + } + + @Autowired + public void setUsersRepository(UsersRepository usersRepository) { + this.usersRepository = usersRepository; + } + + public List getUserAuthorities() { + return userAuthorities; + } + + public void setUserAuthorities(List userAuthorities) { + this.userAuthorities = userAuthorities; + } + + public Set getGroups() { + return groups; + } + + public void setGroups(Set groups) { + this.groups = groups; + } + +} diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/forms/UserFormValidator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/java/org/iri_research/renkan/forms/UserFormValidator.java Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,47 @@ +package org.iri_research.renkan.forms; + +import org.iri_research.renkan.Constants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.validation.Errors; +import org.springframework.validation.ValidationUtils; +import org.springframework.validation.Validator; + +@Component +public class UserFormValidator implements Validator { + + @SuppressWarnings("unused") + private Logger logger = LoggerFactory.getLogger(UserFormValidator.class); + + @Override + public boolean supports(Class clazz) { + return UserForm.class.equals(clazz); + } + + @Override + public void validate(Object target, Errors errors) { + UserForm userForm = (UserForm) target; + + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "title", + "renkan.error.name.empty"); + + //TODO : check for user name unicity + String pswd = userForm.getPassword(); + String pswdConf = userForm.getPasswordConfirm(); + + if( (pswd == null && pswdConf != null) + || ((pswd != null || pswdConf != null) && !pswd.equals(pswdConf))) { + errors.rejectValue("password", "renkan.error.password.equals"); + } + + if(userForm.getId() == null && (pswd == null || pswd.length() == 0)) { + errors.rejectValue("password", "renkan.error.password.missing"); + } + + if(userForm.getUserAuthorities() != null && !Constants.USER_ROLES_ALL.containsAll(userForm.getUserAuthorities())) { + errors.rejectValue("userAuthorities", "renkan.error.authorities.bad_value", "Bad role value"); + } + } + +} diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/management/MigrateRenkanUser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/java/org/iri_research/renkan/management/MigrateRenkanUser.java Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,77 @@ +package org.iri_research.renkan.management; + +import org.iri_research.renkan.models.Project; +import org.iri_research.renkan.models.RenkanUser; +import org.iri_research.renkan.models.User; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.stereotype.Component; + +import com.mongodb.BasicDBObject; +import com.mongodb.DBCollection; +import com.mongodb.DBObject; +import com.mongodb.WriteConcern; + +@Component +public class MigrateRenkanUser { + + public static void main(String[] args) { + + @SuppressWarnings("resource") + ApplicationContext context = new ClassPathXmlApplicationContext( + "classpath:WEB-INF/applicationContext.xml"); + + MigrateRenkanUser p = context.getBean(MigrateRenkanUser.class); + p.start(args); + + } + + @Autowired + private MongoTemplate template; + + private void start(String[] args) { + + DBCollection userColl = template.getCollection(template + .getCollectionName(User.class)); + DBCollection renkanUserColl = template.getCollection(template + .getCollectionName(RenkanUser.class)); + DBCollection projectColl = template.getCollection(template + .getCollectionName(Project.class)); + + for (DBObject user : userColl.find()) { + if (!user.containsField("project_id")) { + continue; + } + String projectId = (String) user.get("project_id"); + if (projectId == null || projectId.isEmpty()) { + user.removeField("project_id"); + userColl.save(user); + continue; + } + DBObject proj = new BasicDBObject(); + proj.put("_id", projectId); + if (projectColl.findOne(proj) != null) { + DBObject renkanUser = new BasicDBObject(); + renkanUser.put("project_id", projectId); + renkanUser.put("user_id", user.get("_id")); + if (renkanUserColl.findOne(renkanUser) == null) { + System.out.println(String.format("%s : %s : %s", + user.get("_id"), user.get("title"), + user.get("project_id"))); + renkanUser = new BasicDBObject(); + renkanUser.put("project_id", user.get("project_id")); + renkanUser.put("user_id", user.get("_id")); + renkanUser.put("color", user.get("color")); + renkanUserColl.insert(renkanUser); + } + user.removeField("project_id"); + userColl.save(user); + } else { + userColl.remove(user, WriteConcern.ACKNOWLEDGED); + } + } + + } +} diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/models/AbstractRenkanModel.java --- a/server/src/main/java/org/iri_research/renkan/models/AbstractRenkanModel.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/models/AbstractRenkanModel.java Wed Jan 15 18:36:27 2014 +0100 @@ -1,82 +1,139 @@ package org.iri_research.renkan.models; import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import javax.crypto.spec.SecretKeySpec; + +import org.apache.commons.codec.binary.Hex; +import org.iri_research.renkan.Constants; +import org.iri_research.renkan.RenkanException; import org.iri_research.renkan.RenkanRuntimeException; +public abstract class AbstractRenkanModel implements + IRenkanModel { -public abstract class AbstractRenkanModel implements IRenkanModel { - - public AbstractRenkanModel(ID id, String title, String description, String uri, String color) { - super(); - this.id = id; - this.title = title; - this.description = description; - this.uri = uri; - this.color = color; - } - - protected AbstractRenkanModel() { - } + public AbstractRenkanModel(ID id, String title, String description, + String uri, String color) { + super(); + this.id = id; + this.title = title; + this.description = description; + this.uri = uri; + this.color = color; + } + + protected AbstractRenkanModel() { + } + + protected ID id; + protected String title; + protected String description; + protected String uri; + protected String color; + + @Override + public String getTitle() { + return this.title; + } - protected ID id; - protected String title; - protected String description; - protected String uri; - protected String color; - - @Override - public String getTitle() { - return this.title; - } + @Override + public String getDescription() { + return this.description; + } + + @Override + public String getUri() { + return this.uri; + } + + @Override + public String getColor() { + return this.color; + } - @Override - public String getDescription() { - return this.description; - } + @Override + public ID getId() { + return this.id; + } + + @Override + public void setId(ID id) throws RenkanRuntimeException { + if (this.id != null) { + throw new RenkanRuntimeException( + "Current id is not null, can not change object id"); + } + this.id = id; + } + + @Override + public void setTitle(String title) { + this.title = title; + } - @Override - public String getUri() { - return this.uri; - } - - @Override - public String getColor() { - return this.color; - } - - @Override - public ID getId() { - return this.id; - } - - @Override - public void setId(ID id) throws RenkanRuntimeException { - if(this.id != null) { - throw new RenkanRuntimeException("Current id is not null, can not change object id"); - } - this.id = id; - } + @Override + public void setDescription(String description) { + this.description = description; + } + + @Override + public void setUri(String uri) { + this.uri = uri; + } + + @Override + public void setColor(String color) { + this.color = color; + } + + abstract protected String getRawKeyPart(); + + private String getRawKey(String salt) { + StringBuffer key = new StringBuffer(salt != null ? salt + "|" : ""); + key.append(this.getId()); + key.append('|'); + key.append(this.getRawKeyPart()); + return key.toString(); + } + + public String getKey(String salt) throws RenkanException { + + String rawKey = this.getRawKey(salt); - @Override - public void setTitle(String title) { - this.title = title; - } - - @Override - public void setDescription(String description) { - this.description = description; - } + MessageDigest md; + try { + md = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException e) { + throw new RenkanException("NoSuchAlgorithmException digest: " + + e.getMessage(), e); + } + String key; + final SecretKeySpec secret_key = new SecretKeySpec( + Constants.KEYHEX.getBytes(), "HmacSHA256"); + md.update(secret_key.getEncoded()); + try { + key = Hex.encodeHexString(md.digest(rawKey.getBytes("UTF-8"))); + } catch (UnsupportedEncodingException e) { + throw new RenkanException("UnsupportedEncodingException digest: " + + e.getMessage(), e); + } - @Override - public void setUri(String uri) { - this.uri = uri; - } + return key; + } + + public boolean checkKey(String key, String salt) throws RenkanException { + + if (key == null || key.isEmpty()) { + return false; + } - @Override - public void setColor(String color) { - this.color = color; - } - - + String signature = key; + + String new_key = this.getKey(salt); + + return new_key.equals(signature); + } + } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/models/Edge.java --- a/server/src/main/java/org/iri_research/renkan/models/Edge.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/models/Edge.java Wed Jan 15 18:36:27 2014 +0100 @@ -9,82 +9,85 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; - -@Document(collection="edges") +@Document(collection = "edges") public class Edge extends AbstractRenkanModel { - @DBRef - private Node from; - - @DBRef - private Node to; - - @Field("project_id") - @JsonProperty("project_id") - private String projectId; - - @Field("created_by") - @JsonProperty("created_by") - private String createdBy; - - @SuppressWarnings("unused") - private Edge() { - } - - public Edge(Edge edge, Node from, Node to, String projectId) { - this(Constants.UUID_GENERATOR.generate().toString(), edge.title, edge.description, edge.uri, edge.color, from, to, edge.createdBy, projectId); - } + @DBRef + private Node from; + + @DBRef + private Node to; + + @Field("project_id") + @JsonProperty("project_id") + private String projectId; + + @Field("created_by") + @JsonProperty("created_by") + private String createdBy; + + @SuppressWarnings("unused") + private Edge() { + } - public Edge(Edge edge) { - this(edge, edge.from, edge.to, edge.projectId); - } + public Edge(Edge edge, Node from, Node to, String projectId) { + this(Constants.UUID_GENERATOR.generate().toString(), edge.title, + edge.description, edge.uri, edge.color, from, to, + edge.createdBy, projectId); + } + + public Edge(Edge edge) { + this(edge, edge.from, edge.to, edge.projectId); + } - @Autowired(required=true) - public Edge(String id, String title, String description, String uri, String color, Node from, Node to, String createdBy, String projectId) { - super(id,title, description, uri, color); - this.from = from; - this.to = to; - this.createdBy = createdBy; - this.projectId = projectId; - } - + @Autowired(required = true) + public Edge(String id, String title, String description, String uri, + String color, Node from, Node to, String createdBy, String projectId) { + super(id, title, description, uri, color); + this.from = from; + this.to = to; + this.createdBy = createdBy; + this.projectId = projectId; + } - @JsonProperty("project_id") - public String getProjectId() { - return projectId; - } + @JsonProperty("project_id") + public String getProjectId() { + return projectId; + } + public String getCreatedBy() { + return createdBy; + } + + @JsonIgnore + public Node getFromNode() { + return this.from; + } - public String getCreatedBy() { - return createdBy; - } - - @JsonIgnore - public Node getFromNode() { - return this.from; - } - - public String getFrom() { - if(this.from != null) { - return this.from.id; - } - else { - return null; - } - } + public String getFrom() { + if (this.from != null) { + return this.from.id; + } else { + return null; + } + } + + @JsonIgnore + public Node getToNode() { + return this.to; + } - @JsonIgnore - public Node getToNode() { - return this.to; - } - - public String getTo() { - if(this.to != null) { - return this.to.id; - } - else { - return null; - } - } - + public String getTo() { + if (this.to != null) { + return this.to.id; + } else { + return null; + } + } + + @Override + protected String getRawKeyPart() { + return this.createdBy; + } + } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/models/Group.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/java/org/iri_research/renkan/models/Group.java Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,66 @@ +package org.iri_research.renkan.models; + +import java.util.Set; +import java.util.TreeSet; + +import org.springframework.data.mongodb.core.mapping.Document; + +@Document(collection = "groups") +public class Group extends AbstractRenkanModel { + + private String avatar; + private Set users = new TreeSet<>(); + + public Group() { + } + + public Group(String id, String title, String description, String uri, + String color) { + super(id, title, description, uri, color); + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public String getGroupName() { + return this.getTitle(); + } + + @Override + protected String getRawKeyPart() { + return this.id; + } + + public Set getUsers() { + if(this.users == null) { + this.users = new TreeSet<>(); + } + return this.users; + } + + + public boolean addUser(User user) { + return this.addUser(user.getId()); + } + + public boolean addUser(String userId) { + return this.getUsers().add(userId); + } + + public boolean removeUser(User user) { + return this.removeUser(user.getId()); + } + + public boolean removeUser(String userId) { + if(this.getUsers() != null) { + return this.getUsers().remove(userId); + } + return false; + } + +} diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/models/IRenkanModel.java --- a/server/src/main/java/org/iri_research/renkan/models/IRenkanModel.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/models/IRenkanModel.java Wed Jan 15 18:36:27 2014 +0100 @@ -2,28 +2,41 @@ import java.io.Serializable; +import org.iri_research.renkan.RenkanException; import org.iri_research.renkan.RenkanRuntimeException; - public interface IRenkanModel { - - public ID getId(); - /** - * Set the object id. - * This method must throw a RenkanException if the current object id is not null - * @param id - * @throws RenkanRuntimeException if the current id is not null - */ - public void setId(ID id) throws RenkanRuntimeException; - public String getTitle(); - public String getDescription(); - public String getUri(); - public String getColor(); + + public ID getId(); + + /** + * Set the object id. This method must throw a RenkanException if the + * current object id is not null + * + * @param id + * @throws RenkanRuntimeException + * if the current id is not null + */ + public void setId(ID id) throws RenkanRuntimeException; + + public String getTitle(); + + public String getDescription(); - public void setTitle(String title); - public void setDescription(String description); - public void setUri(String uri); - public void setColor(String color); + public String getUri(); + + public String getColor(); + + public void setTitle(String title); + + public void setDescription(String description); - + public void setUri(String uri); + + public void setColor(String color); + + public String getKey(String salt) throws RenkanException; + + public boolean checkKey(String key, String salt) throws RenkanException; + } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/models/Node.java --- a/server/src/main/java/org/iri_research/renkan/models/Node.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/models/Node.java Wed Jan 15 18:36:27 2014 +0100 @@ -8,66 +8,75 @@ import com.fasterxml.jackson.annotation.JsonProperty; -@Document(collection="nodes") +@Document(collection = "nodes") public class Node extends AbstractRenkanModel { - public Node(Node node, String projectId) { - this(Constants.UUID_GENERATOR.generate().toString(), node.title, node.description, node.uri, node.color, node.createdBy, node.position, node.image, node.size, projectId); - } - - public Node(Node node) { - this(node, node.projectId); - } - - @SuppressWarnings("unused") - private Node() { - } + public Node(Node node, String projectId) { + this(Constants.UUID_GENERATOR.generate().toString(), node.title, + node.description, node.uri, node.color, node.createdBy, + node.position, node.image, node.size, projectId); + } + + public Node(Node node) { + this(node, node.projectId); + } + + @SuppressWarnings("unused") + private Node() { + } - @Autowired(required=true) - public Node(String id, String title, String description, String uri, String color, String createdBy, Point position, String image, Integer size, String projectId) { - super(id, title, description, uri, color); - - this.projectId = projectId; - this.createdBy = createdBy; - this.position = position; - this.image = image; - this.size = (size == null) ? 0 : size.intValue(); - } + @Autowired(required = true) + public Node(String id, String title, String description, String uri, + String color, String createdBy, Point position, String image, + Integer size, String projectId) { + super(id, title, description, uri, color); - @Field("project_id") - @JsonProperty("project_id") - private String projectId = null; + this.projectId = projectId; + this.createdBy = createdBy; + this.position = position; + this.image = image; + this.size = (size == null) ? 0 : size.intValue(); + } + + @Field("project_id") + @JsonProperty("project_id") + private String projectId = null; + + @Field("created_by") + @JsonProperty("created_by") + private String createdBy = null; - @Field("created_by") - @JsonProperty("created_by") - private String createdBy = null; - - private Point position = null; + private Point position = null; + + private String image; + + private int size; - private String image; - - private int size; - - public Point getPosition() { - return position; - } + public Point getPosition() { + return position; + } + + public String getImage() { + return image; + } - public String getImage() { - return image; - } + @JsonProperty("project_id") + public String getProjectId() { + return projectId; + } - @JsonProperty("project_id") - public String getProjectId() { - return projectId; - } + @JsonProperty("created_by") + public String getCreatedBy() { + return createdBy; + } - @JsonProperty("created_by") - public String getCreatedBy() { - return createdBy; - } + public int getSize() { + return size; + } - public int getSize() { - return size; - } - + @Override + protected String getRawKeyPart() { + return this.createdBy; + } + } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/models/Project.java --- a/server/src/main/java/org/iri_research/renkan/models/Project.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/models/Project.java Wed Jan 15 18:36:27 2014 +0100 @@ -4,7 +4,6 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; -import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -15,6 +14,8 @@ import org.iri_research.renkan.Constants; import org.iri_research.renkan.Constants.EditMode; import org.iri_research.renkan.RenkanException; +import org.iri_research.renkan.utils.ColorGenerator; +import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -22,165 +23,240 @@ import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Field; +import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; -@Document(collection="projects") +@Document(collection = "projects") public class Project extends AbstractRenkanModel { - - @SuppressWarnings("unused") - private static Logger logger = LoggerFactory.getLogger(Project.class); - - @Field("rev_counter") - private int revCounter = 1; - - private Date created; - private Date updated; - - // Space - @Field("space_id") - @JsonProperty("space_id") - private String spaceId = null; - - // Nodes - @DBRef - private List nodes = new ArrayList(); - - // edges - @DBRef - private List edges = new ArrayList(); + + @SuppressWarnings("unused") + private static Logger logger = LoggerFactory.getLogger(Project.class); + + @Field("rev_counter") + private int revCounter = 1; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone = "GMT") + private DateTime created; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone = "GMT") + private DateTime updated; + + // Space + @Field("space_id") + @JsonProperty("space_id") + private String spaceId = null; + + // Nodes + @DBRef + private List nodes = new ArrayList(); + + // edges + @DBRef + private List edges = new ArrayList(); + + // Users + private List users = new ArrayList(); + + public Project(Project project) { + this(project.spaceId, Constants.UUID_GENERATOR.generate().toString(), + project.title, project.description, project.uri, new DateTime()); + + Map nodeCloneMap = new HashMap( + project.nodes.size()); + for (Node node : project.nodes) { + Node newNode = new Node(node, this.id); + this.nodes.add(newNode); + nodeCloneMap.put(node.id, newNode); + } + + for (Edge edge : project.edges) { + this.edges.add(new Edge(edge, nodeCloneMap.get(edge.getFrom()), + nodeCloneMap.get(edge.getTo()), this.id)); + } + for (RenkanUser user : project.users) { + this.users.add(new RenkanUser(user)); + } + } - // Users - @DBRef - private List users = new ArrayList(); - - - public Project(Project project) { - this(project.spaceId, Constants.UUID_GENERATOR.generate().toString(), project.title, project.description, project.uri, new Date()); - - Map nodeCloneMap = new HashMap(project.nodes.size()); - for (Node node : project.nodes) { - Node newNode = new Node(node,this.id); - this.nodes.add(newNode); - nodeCloneMap.put(node.id, newNode); - } + public Project(String spaceId, String id, String title, String description, + String uri, DateTime created, int revCounter) { + super(id, title, description, uri, null); + this.revCounter = revCounter; + this.spaceId = spaceId; + this.created = created; + if (this.created == null) { + this.created = new DateTime(); + } + this.setUpdated(new DateTime()); + } + + @Autowired(required = true) + public Project(String spaceId, String id, String title, String description, + String uri, DateTime created) { + this(spaceId, id, title, description, uri, created, 1); + } + + @SuppressWarnings("unused") + private Project() { + } + + public int getRevCounter() { + return this.revCounter; + } + + public List getNodes() { + return this.nodes; + } - for (Edge edge : project.edges) { - this.edges.add(new Edge(edge, nodeCloneMap.get(edge.getFrom()), nodeCloneMap.get(edge.getTo()), this.id)); - } - for(User user : project.users) { - this.users.add(user); - } - } - - public Project(String spaceId, String id, String title, String description, String uri, Date created, - int revCounter) { - super(id,title, description, uri, null); - this.revCounter = revCounter; - this.spaceId = spaceId; - this.created = created; - if(this.created == null) { - this.created = new Date(); - } - this.setUpdated(new Date()); - } + public List getEdges() { + return this.edges; + } + + public List getUsers() { + return this.users; + } + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone = "GMT") + public DateTime getCreated() { + return created; + } + + public void setCreated(DateTime date) { + this.created = date; - @Autowired(required=true) - public Project(String spaceId, String id, String title, String description, String uri, Date created) { - this(spaceId, id,title, description, uri, created, 1); - } - - @SuppressWarnings("unused") - private Project() { - } - - public int getRevCounter() { - return this.revCounter; - } - - public List getNodes() { - return this.nodes; - } + } + + @JsonProperty("space_id") + public String getSpaceId() { + return spaceId; + } + + private String getRawKey(String prefix, Constants.EditMode editMode) { + StringBuffer key = new StringBuffer(prefix != null ? prefix + "|" : ""); + key.append(this.getId()); + key.append('|'); + key.append(this.getSpaceId()); + key.append('|'); + key.append(this.getCreated().getMillis()); + key.append('|'); + key.append(editMode.toString()); + return key.toString(); + } - public List getEdges() { - return this.edges; - } - - public List getUsers() { - return this.users; - } + public String getKey(int editMode) throws RenkanException { + return this.getKey(EditMode.fromInt(editMode)); + } + + public String getKey(Constants.EditMode editMode) throws RenkanException { + + String rawKey = this.getRawKey("", editMode); + + MessageDigest md; + try { + md = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException e) { + throw new RenkanException("NoSuchAlgorithmException digest: " + + e.getMessage(), e); + } + String key; + final SecretKeySpec secret_key = new SecretKeySpec( + Constants.KEYHEX.getBytes(), "HmacSHA256"); + md.update(secret_key.getEncoded()); + try { + key = Hex.encodeHexString(md.digest(rawKey.getBytes("UTF-8"))); + } catch (UnsupportedEncodingException e) { + throw new RenkanException("UnsupportedEncodingException digest: " + + e.getMessage(), e); + } - public Date getCreated() { - return created; - } - - public void setCreated(Date date) { - this.created = date; - - } - - @JsonProperty("space_id") - public String getSpaceId() { - return spaceId; - } + return key; + } + + public boolean checkKey(String key, Constants.EditMode editMode) + throws RenkanException { + + if (key == null || key.isEmpty()) { + return false; + } + + String signature = key; + + String new_key = this.getKey(editMode); + + return new_key.equals(signature); + } + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone = "GMT") + public DateTime getUpdated() { + return updated; + } + + public void setUpdated(DateTime updated) { + this.updated = updated; + } + + public void addUser(User user) { - private String getRawKey(String prefix, Constants.EditMode editMode) { - StringBuffer key = new StringBuffer(prefix!=null?prefix+"|":""); - key.append(this.getId()); - key.append('|'); - key.append(this.getSpaceId()); - key.append('|'); - key.append(this.getCreated().getTime()); - key.append('|'); - key.append(editMode.toString()); - return key.toString(); - } - - public String getKey(int editMode) throws RenkanException { - return this.getKey(EditMode.fromInt(editMode)); - } - - public String getKey(Constants.EditMode editMode) throws RenkanException { - - String rawKey = this.getRawKey("", editMode); - - MessageDigest md; - try { - md = MessageDigest.getInstance("SHA-256"); - } catch (NoSuchAlgorithmException e) { - throw new RenkanException("NoSuchAlgorithmException digest: " + e.getMessage(), e); - } - String key; - final SecretKeySpec secret_key = new SecretKeySpec(Constants.KEYHEX.getBytes(), "HmacSHA256"); - md.update(secret_key.getEncoded()); - try { - key = Hex.encodeHexString(md.digest(rawKey.getBytes("UTF-8"))); - } catch (UnsupportedEncodingException e) { - throw new RenkanException("UnsupportedEncodingException digest: " + e.getMessage(), e); - } - - return key; - } - - public boolean checkKey(String key, Constants.EditMode editMode) throws RenkanException { - + if (user == null) { + // we add an anonymous user + // find an unique user name + this.addUser(null, null); + } else { + // if user is already in list do nothing + for (RenkanUser renkanUser : this.users) { + if (renkanUser.getUserId() != null + && renkanUser.getUserId().equals(user.getId())) { + return; + } + } + // user not found + this.users.add(new RenkanUser(this.getId(), user.getId(), user + .getColor(), user.getUsername())); + + } + + } + + public void addUser(String username, String color) { - if(key == null || key.isEmpty()) { - return false; - } - - String signature = key; - - String new_key = this.getKey(editMode); - - return new_key.equals(signature); - } + if (username == null) { + // find a new username + int i = 0; + boolean usernameFound = true; + while (i++ < 1000000 && usernameFound) { + username = String.format("%s-%s", + Constants.ANONYMOUS_USER_BASE_NAME, i); + usernameFound = false; + for (RenkanUser renkanUser : this.users) { + if (username.equals(renkanUser.getUsername())) { + usernameFound = true; + break; + } + } + } + } - public Date getUpdated() { - return updated; - } + if (color == null) { + int i = 0; + boolean colorFound = true; + while (i++ < 10000000 && colorFound) { + color = "#" + ColorGenerator.randomColorHex(); + colorFound = false; + for (RenkanUser renkanUser : this.users) { + if (username.equals(renkanUser.getUsername())) { + colorFound = true; + break; + } + } + } + } - public void setUpdated(Date updated) { - this.updated = updated; - } - + RenkanUser ruser = new RenkanUser(this.getId(), null, color, username); + this.users.add(ruser); + } + + @Override + protected String getRawKeyPart() { + return this.getId() + Long.toString(this.getCreated().getMillis()); + } + } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/models/ProjectRevision.java --- a/server/src/main/java/org/iri_research/renkan/models/ProjectRevision.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/models/ProjectRevision.java Wed Jan 15 18:36:27 2014 +0100 @@ -5,69 +5,79 @@ import java.util.List; import org.bson.types.ObjectId; +import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.mongodb.core.mapping.DBRef; import org.springframework.data.mongodb.core.mapping.Document; -@Document(collection="projectRevisions") +import com.fasterxml.jackson.annotation.JsonFormat; + +@Document(collection = "projectRevisions") public class ProjectRevision extends AbstractRenkanModel { - @SuppressWarnings("unused") - private static Logger logger = LoggerFactory.getLogger(ProjectRevision.class); - - private int revision; - - @DBRef - private Project project; - - private Date created; - - // Nodes - private List nodes = new ArrayList(); - - // Edgess - private List edges = new ArrayList(); + @SuppressWarnings("unused") + private static Logger logger = LoggerFactory + .getLogger(ProjectRevision.class); + + private int revision; + + @DBRef + private Project project; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone = "GMT") + private DateTime created; + // Nodes + private List nodes = new ArrayList(); - @SuppressWarnings("unused") - private ProjectRevision() { - super(); - } + // Edgess + private List edges = new ArrayList(); + + @SuppressWarnings("unused") + private ProjectRevision() { + super(); + } + + public ProjectRevision(String title, String description, String uri, + Project project, int revision, Date created) { + this(null, title, description, uri, project, revision, created); + } - public ProjectRevision(String title, String description, - String uri, Project project, int revision, Date created) { - this(null, title, description, uri, project, revision,created); - } - - public ProjectRevision(ObjectId id, String title, String description, - String uri, Project project, int revision, Date created) { - super(id, title, description, uri, null); - this.project = project; - this.revision = revision; - if(created == null) { - this.created = new Date(System.currentTimeMillis()); - } - } + public ProjectRevision(ObjectId id, String title, String description, + String uri, Project project, int revision, Date created) { + super(id, title, description, uri, null); + this.project = project; + this.revision = revision; + if (created == null) { + this.created = new DateTime(System.currentTimeMillis()); + } + } + + public int getRevision() { + return revision; + } + + public Project getProject() { + return project; + } - public int getRevision() { - return revision; - } - - public Project getProject() { - return project; - } - - public List getNodes() { - return nodes; - } + public List getNodes() { + return nodes; + } + + public List getEgdes() { + return edges; + } - public List getEgdes() { - return edges; - } + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone = "GMT") + public DateTime getCreated() { + return created; + } - public Date getCreated() { - return created; - } - + @Override + protected String getRawKeyPart() { + return Long.toString(this.getCreated().getMillis()); + } + } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/models/ProjectSync.java --- a/server/src/main/java/org/iri_research/renkan/models/ProjectSync.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/models/ProjectSync.java Wed Jan 15 18:36:27 2014 +0100 @@ -1,60 +1,60 @@ package org.iri_research.renkan.models; -import java.util.Date; - import org.bson.types.ObjectId; +import org.joda.time.DateTime; import org.springframework.data.mongodb.core.mapping.DBRef; import org.springframework.data.mongodb.core.mapping.Document; +import com.fasterxml.jackson.annotation.JsonFormat; -@Document(collection="projectSyncs") +@Document(collection = "projectSyncs") public class ProjectSync { - private ObjectId id; - - private String data; - - @DBRef - private Project project; - - private int revision; - - private Date created; - - private String user; + private ObjectId id; + + private String data; + + @DBRef + private Project project; + + private int revision; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone = "GMT") + private DateTime created; + + private String user; - public ProjectSync(ObjectId id, String data, Project project, int revision, - Date created, String user) { - this.id = id; - this.data = data; - this.project = project; - this.revision = revision; - this.created = created; - this.user = user; - if(this.created == null) { - this.created = new Date(System.currentTimeMillis()); - } - } + public ProjectSync(ObjectId id, String data, Project project, int revision, + DateTime created, String user) { + this.id = id; + this.data = data; + this.project = project; + this.revision = revision; + this.created = created; + this.user = user; + if (this.created == null) { + this.created = new DateTime(System.currentTimeMillis()); + } + } - public ObjectId getId() { - return id; - } + public ObjectId getId() { + return id; + } - public String getData() { - return data; - } + public String getData() { + return data; + } - public Project getProject() { - return project; - } + public Project getProject() { + return project; + } - public int getRevision() { - return revision; - } + public int getRevision() { + return revision; + } - public String getUser() { - return user; - } - - + public String getUser() { + return user; + } + } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/models/RenkanSessionModeratorState.java --- a/server/src/main/java/org/iri_research/renkan/models/RenkanSessionModeratorState.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/models/RenkanSessionModeratorState.java Wed Jan 15 18:36:27 2014 +0100 @@ -5,23 +5,22 @@ import java.util.Map; public enum RenkanSessionModeratorState { - INSTANCE; - - private Map usersActivationMap = new HashMap(); - private Map> projectsActivationMap = new HashMap>(); - private Map> projectsUsersList = new HashMap>(); - - public Map getUsersActivationMap() { - return usersActivationMap; - } + INSTANCE; + + private Map usersActivationMap = new HashMap(); + private Map> projectsActivationMap = new HashMap>(); + private Map> projectsUsersList = new HashMap>(); + + public Map getUsersActivationMap() { + return usersActivationMap; + } - public Map> getProjectsActivationMap() { - return projectsActivationMap; - } + public Map> getProjectsActivationMap() { + return projectsActivationMap; + } - public Map> getProjectsUsersList() { - return projectsUsersList; - } - - + public Map> getProjectsUsersList() { + return projectsUsersList; + } + } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/models/RenkanUser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/java/org/iri_research/renkan/models/RenkanUser.java Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,61 @@ +package org.iri_research.renkan.models; + +import org.springframework.data.mongodb.core.mapping.Field; + +public class RenkanUser { + + @Field(value = "user_id") + private String userId; + private String color; + private String username; + + @SuppressWarnings("unused") + private RenkanUser() { + } + + public RenkanUser(String projectId, String userId, String color, + String username) { + this.userId = userId; + this.color = color; + this.username = username; + } + + public RenkanUser(RenkanUser user) { + if (user != null) { + this.setUserId(user.getUserId()); + this.setColor(user.getColor()); + this.setUsername(user.getUsername()); + } + } + + @Field(value = "user_id") + public String getUserId() { + return userId; + } + + @Field(value = "user_id") + public void setUserId(String userId) { + this.userId = userId; + } + + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public boolean isAnonymous() { + return this.getUserId() == null; + } + +} diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/models/RosterUser.java --- a/server/src/main/java/org/iri_research/renkan/models/RosterUser.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/models/RosterUser.java Wed Jan 15 18:36:27 2014 +0100 @@ -1,46 +1,56 @@ package org.iri_research.renkan.models; +import com.fasterxml.jackson.annotation.JsonProperty; + public class RosterUser extends AbstractRenkanModel { - - private String project_id; - private Long site_id; - private String client_id; + + private String projectId; + private Long siteId; + private String clientId; + + public RosterUser(String id, String title, String description, String uri, + String color, String project_id, Long site_id, String client_id) { + super(id, title, description, uri, color); - public RosterUser(String id, String title, String description, String uri, String color, String project_id, Long site_id, String client_id) { - super(id, title, description, uri, color); - - this.project_id = project_id; - this.site_id = site_id; - this.client_id = client_id; - } - - public void setTitle(String title) { - this.title = title; - } + this.projectId = project_id; + this.siteId = site_id; + this.clientId = client_id; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setUri(String uri) { + this.uri = uri; + } - public void setDescription(String description) { - this.description = description; - } - - public void setUri(String uri) { - this.uri = uri; - } - - public void setColor(String color) { - this.color = color; - } + public void setColor(String color) { + this.color = color; + } + + @JsonProperty(value = "project_id") + public String getProjectId() { + return projectId; + } - public String getProject_id() { - return project_id; - } + @JsonProperty(value = "site_id") + public Long getSiteId() { + return siteId; + } - public Long getSite_id() { - return site_id; - } - - public String getClient_id() { - return client_id; - } + @JsonProperty(value = "client_id") + public String getClientId() { + return clientId; + } - + @Override + protected String getRawKeyPart() { + return this.id; + } + } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/models/Space.java --- a/server/src/main/java/org/iri_research/renkan/models/Space.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/models/Space.java Wed Jan 15 18:36:27 2014 +0100 @@ -1,124 +1,82 @@ package org.iri_research.renkan.models; -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Date; - -import javax.crypto.spec.SecretKeySpec; - -import org.apache.commons.codec.binary.Hex; -import org.iri_research.renkan.Constants; -import org.iri_research.renkan.RenkanException; +import org.joda.time.DateTime; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Field; +import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; -@Document(collection="spaces") +@Document(collection = "spaces") public class Space extends AbstractRenkanModel { - - @Autowired - public Space(String id, String title, String description, String binConfig, String uri, String color, String createdBy, String image, Date created) { - super(id, title, description, uri, color); - - this.binConfig = binConfig; - this.createdBy = createdBy; - this.setImage(image); - this.created = created; - if(this.created == null) { - this.created = new Date(); - } - } - - public Space() { - } + + @Autowired + public Space(String id, String title, String description, String binConfig, + String uri, String color, String createdBy, String image, + DateTime created) { + super(id, title, description, uri, color); - @Field("bin_config") - @JsonProperty("bin_config") - private String binConfig; - - @Field("created_by") - @JsonProperty("created_by") - private String createdBy = null; - private String image; - private Date created; - - public String getImage() { - return image; - } + this.binConfig = binConfig; + this.createdBy = createdBy; + this.setImage(image); + this.created = created; + if (this.created == null) { + this.created = new DateTime(); + } + } + + public Space() { + } - @JsonProperty("created_by") - public String getCreatedBy() { - return createdBy; - } - - public Date getCreated() { - return created; - } - - public void setCreated(Date date) { - this.created = date; - - } + @Field("bin_config") + @JsonProperty("bin_config") + private String binConfig; - @JsonProperty("bin_config") - public String getBinConfig() { - return binConfig; - } + @Field("created_by") + @JsonProperty("created_by") + private String createdBy = null; + private String image; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone = "GMT") + private DateTime created; - @JsonProperty("bin_config") - public void setBinConfig(String bin_config) { - this.binConfig = bin_config; - } + public String getImage() { + return image; + } + + @JsonProperty("created_by") + public String getCreatedBy() { + return createdBy; + } + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone = "GMT") + public DateTime getCreated() { + return created; + } + + public void setCreated(DateTime date) { + this.created = date; + + } - public void setImage(String image) { - this.image = image; - } - - private String getRawKey(String salt) { - StringBuffer key = new StringBuffer(salt!=null?salt+"|":""); - key.append(this.getId()); - key.append('|'); - key.append(this.getCreated().getTime()); - return key.toString(); - } - - public String getKey(String salt) throws RenkanException { - - String rawKey = this.getRawKey(salt); - - MessageDigest md; - try { - md = MessageDigest.getInstance("SHA-256"); - } catch (NoSuchAlgorithmException e) { - throw new RenkanException("NoSuchAlgorithmException digest: " + e.getMessage(), e); - } - String key; - final SecretKeySpec secret_key = new SecretKeySpec(Constants.KEYHEX.getBytes(), "HmacSHA256"); - md.update(secret_key.getEncoded()); - try { - key = Hex.encodeHexString(md.digest(rawKey.getBytes("UTF-8"))); - } catch (UnsupportedEncodingException e) { - throw new RenkanException("UnsupportedEncodingException digest: " + e.getMessage(), e); - } - - return key; - } - - public boolean checkKey(String key, String salt) throws RenkanException { - + @JsonProperty("bin_config") + public String getBinConfig() { + return binConfig; + } + + @JsonProperty("bin_config") + public void setBinConfig(String bin_config) { + this.binConfig = bin_config; + } - if(key == null || key.isEmpty()) { - return false; - } - - String signature = key; - - String new_key = this.getKey(salt); - - return new_key.equals(signature); - } - + public void setImage(String image) { + this.image = image; + } + + @Override + protected String getRawKeyPart() { + return this.id+Long.toString(this.getCreated().getMillis()); + } + } \ No newline at end of file diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/models/User.java --- a/server/src/main/java/org/iri_research/renkan/models/User.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/models/User.java Wed Jan 15 18:36:27 2014 +0100 @@ -1,24 +1,204 @@ package org.iri_research.renkan.models; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import org.iri_research.renkan.Constants; +import org.joda.time.LocalDate; import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.Field; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; + +@Document(collection = "users") +public class User extends AbstractRenkanModel implements UserDetails { + + public static class UserComparator implements Comparator { + + @Override + public int compare(User u1, User u2) { + if(u1 == null || u1.getId() == null) { + return (u2==null || u2.getId() == null)? 0 : Integer.MIN_VALUE; + } + else { + return u2==null?Integer.MAX_VALUE:u1.getId().compareTo(u2.getId()); + } + + } + + } -@Document(collection="users") -public class User extends AbstractRenkanModel { - - private String project_id; + private static final long serialVersionUID = 6972038893086220548L; + + + private String avatar; + @Field("credentials_expiration_date") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone = "GMT") + private LocalDate credentialsExpirationDate; + private String email; + private boolean enabled; + @Field("expiration_date") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone = "GMT") + private LocalDate expirationDate; + private boolean locked; + private String password; + @Field("authorities") + private List userAuthorities; + + private Set groups = new TreeSet<>(); + + public User() { + } + + public User(String id, String title, String description, String uri, + String color) { + super(id, title, description, uri, color); + } + + @Override + public Collection getAuthorities() { + List authorities = new ArrayList(); + boolean hasUserRole = false; + for (String role : this.getUserAuthorities()) { + hasUserRole = hasUserRole || Constants.ROLE_USER.equals(role); + authorities.add(new SimpleGrantedAuthority(role)); + } + if(!hasUserRole) { + authorities.add(new SimpleGrantedAuthority(Constants.ROLE_USER)); + } + + return authorities; + } + + public String getAvatar() { + return avatar; + } + + public String getColor() { + return this.color; + } + + public LocalDate getCredentialsExpirationDate() { + return credentialsExpirationDate; + } + + public String getEmail() { + return email; + } + + public LocalDate getExpirationDate() { + return expirationDate; + } - public User(String id, String title, String description, String uri, String color, String project_id) { - super(id, title, description, uri, color); - - this.project_id = project_id; - } - - public String getColor() { - return this.color; - } + @Override + @JsonIgnore + public String getPassword() { + return this.password; + } + + @Override + protected String getRawKeyPart() { + return this.id; + } + + public List getUserAuthorities() { + return userAuthorities; + } + + @Override + @JsonIgnore + public String getUsername() { + return this.title; + } + + @Override + public boolean isAccountNonExpired() { + return this.expirationDate == null + || this.expirationDate.isAfter(LocalDate.now()); + } + + @Override + public boolean isAccountNonLocked() { + return !this.locked; + } + + @Override + public boolean isCredentialsNonExpired() { + return this.credentialsExpirationDate == null + || this.credentialsExpirationDate.isAfter(LocalDate.now()); + } + + @Override + public boolean isEnabled() { + return this.enabled; + } + + public boolean isLocked() { + return locked; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } - public String getProject_id() { - return project_id; - } - + public void setCredentialsExpirationDate(LocalDate credentialsExpirationDate) { + this.credentialsExpirationDate = credentialsExpirationDate; + } + + public void setEmail(String email) { + this.email = email; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public void setExpirationDate(LocalDate expirationDate) { + this.expirationDate = expirationDate; + } + + public void setLocked(boolean locked) { + this.locked = locked; + } + + public void setPassword(String password) { + this.password = password; + } + + public void setUserAuthorities(List userAuthorities) { + this.userAuthorities = userAuthorities; + } + + public Set getGroups() { + if(this.groups == null) { + this.groups = new TreeSet<>(); + } + return groups; + } + + + public boolean addGroup(Group g) { + return this.addGroup(g.getId()); + } + + public boolean addGroup(String groupId) { + return this.getGroups().add(groupId); + } + + public boolean removeGroup(Group g) { + return this.removeGroup(g.getId()); + } + + public boolean removeGroup(String groupId) { + return (this.groups == null)?false:this.groups.remove(groupId); + } + } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/repositories/GroupsRepository.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/java/org/iri_research/renkan/repositories/GroupsRepository.java Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,15 @@ +package org.iri_research.renkan.repositories; + +import java.util.List; + +import org.iri_research.renkan.models.Group; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +public interface GroupsRepository extends IRenkanRepository, GroupsRepositoryCustom { + + public List findByTitle(String title); + + public Page findByTitle(String title, Pageable p); + +} diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/repositories/GroupsRepositoryCustom.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/java/org/iri_research/renkan/repositories/GroupsRepositoryCustom.java Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,17 @@ +package org.iri_research.renkan.repositories; + +import java.util.Collection; +import java.util.Map; + +import org.iri_research.renkan.models.Group; +import org.iri_research.renkan.models.User; + +public interface GroupsRepositoryCustom { + /** + * Set the list of user for the group + * @param group: the group. + * @param userIds: the collection of user ids. This parameter must not be null. + */ + public void setUsersList(Group group, Collection userIds); + public Map getUsersMap(Group group); +} diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/repositories/GroupsRepositoryImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/java/org/iri_research/renkan/repositories/GroupsRepositoryImpl.java Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,66 @@ +package org.iri_research.renkan.repositories; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.collections4.IteratorUtils; +import org.iri_research.renkan.models.Group; +import org.iri_research.renkan.models.User; +import org.springframework.beans.factory.annotation.Autowired; + +public class GroupsRepositoryImpl implements GroupsRepositoryCustom { + + @Autowired + private UsersRepository usersRepository; + + @Autowired + private GroupsRepository groupsRepository; + + @Override + // TODO: implement a transaction mecanism... + public void setUsersList(Group group, Collection userIds) { + + assert userIds != null : "list of user ids must not be null"; + + // takes previous user list + List oldUsers = new ArrayList<>(group.getUsers()); + + // calculate difference between two list + List userIdDel = new ArrayList<>(oldUsers); + userIdDel.removeAll(userIds); + + List userIdAdd = new ArrayList<>(userIds); + userIdAdd.removeAll(oldUsers); + + List userAdd = IteratorUtils.toList(this.usersRepository.findAll(userIdAdd).iterator()); + for (User user : userAdd) { + user.addGroup(group.getId()); + } + this.usersRepository.save(userAdd); + List userDel = IteratorUtils.toList(this.usersRepository.findAll(userIdDel).iterator()); + for (User user : userDel) { + user.removeGroup(group.getId()); + } + this.usersRepository.save(userDel); + + group.getUsers().clear(); + group.getUsers().addAll(userIds); + + this.groupsRepository.save(group); + } + + @Override + public Map getUsersMap(Group group) { + HashMap res = new HashMap<>(group.getUsers().size()); + + for (User user : this.usersRepository.findAll(group.getUsers())) { + res.put(user.getId(), user); + } + + return res; + } + +} diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/repositories/IRenkanRepository.java --- a/server/src/main/java/org/iri_research/renkan/repositories/IRenkanRepository.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/repositories/IRenkanRepository.java Wed Jan 15 18:36:27 2014 +0100 @@ -7,7 +7,7 @@ import com.mongodb.DBCollection; public interface IRenkanRepository extends - PagingAndSortingRepository { + PagingAndSortingRepository { - public DBCollection getCollection(); + public DBCollection getCollection(); } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/repositories/ProjectRevisionsRepository.java --- a/server/src/main/java/org/iri_research/renkan/repositories/ProjectRevisionsRepository.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/repositories/ProjectRevisionsRepository.java Wed Jan 15 18:36:27 2014 +0100 @@ -3,8 +3,8 @@ import org.bson.types.ObjectId; import org.iri_research.renkan.models.ProjectRevision; -public interface ProjectRevisionsRepository extends - IRenkanRepository, - ProjectRevisionsRepositoryCustom { +public interface ProjectRevisionsRepository extends + IRenkanRepository, + ProjectRevisionsRepositoryCustom { } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/repositories/ProjectRevisionsRepositoryCustom.java --- a/server/src/main/java/org/iri_research/renkan/repositories/ProjectRevisionsRepositoryCustom.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/repositories/ProjectRevisionsRepositoryCustom.java Wed Jan 15 18:36:27 2014 +0100 @@ -4,7 +4,7 @@ import org.iri_research.renkan.models.ProjectRevision; public interface ProjectRevisionsRepositoryCustom { - - public ProjectRevision getProjectRevision(Project project, int revision); - + + public ProjectRevision getProjectRevision(Project project, int revision); + } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/repositories/ProjectRevisionsRepositoryImpl.java --- a/server/src/main/java/org/iri_research/renkan/repositories/ProjectRevisionsRepositoryImpl.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/repositories/ProjectRevisionsRepositoryImpl.java Wed Jan 15 18:36:27 2014 +0100 @@ -8,20 +8,15 @@ @Component public class ProjectRevisionsRepositoryImpl implements - ProjectRevisionsRepositoryCustom { - - @Override - public ProjectRevision getProjectRevision(Project project, int revision) { - ProjectRevision pr = new ProjectRevision( - project.getTitle(), - project.getDescription(), - project.getUri(), - project, - revision, - new Date(System.currentTimeMillis()) - ); - - return pr; - } + ProjectRevisionsRepositoryCustom { + + @Override + public ProjectRevision getProjectRevision(Project project, int revision) { + ProjectRevision pr = new ProjectRevision(project.getTitle(), + project.getDescription(), project.getUri(), project, revision, + new Date(System.currentTimeMillis())); + + return pr; + } } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/repositories/ProjectSyncsRepository.java --- a/server/src/main/java/org/iri_research/renkan/repositories/ProjectSyncsRepository.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/repositories/ProjectSyncsRepository.java Wed Jan 15 18:36:27 2014 +0100 @@ -3,8 +3,7 @@ import org.bson.types.ObjectId; import org.iri_research.renkan.models.ProjectSync; -public interface ProjectSyncsRepository extends - IRenkanRepository, - ProjectSyncsRepositoryCustom { +public interface ProjectSyncsRepository extends + IRenkanRepository, ProjectSyncsRepositoryCustom { } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/repositories/ProjectSyncsRepositoryCustom.java --- a/server/src/main/java/org/iri_research/renkan/repositories/ProjectSyncsRepositoryCustom.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/repositories/ProjectSyncsRepositoryCustom.java Wed Jan 15 18:36:27 2014 +0100 @@ -5,9 +5,11 @@ import org.iri_research.renkan.models.ProjectSync; public interface ProjectSyncsRepositoryCustom { - - public ProjectSync getProjectSync(String data, Project project, String user) throws RenkanException; - - public ProjectSync getProjectSync(String data, String project_id, String user) throws RenkanException; - + + public ProjectSync getProjectSync(String data, Project project, String user) + throws RenkanException; + + public ProjectSync getProjectSync(String data, String project_id, + String user) throws RenkanException; + } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/repositories/ProjectSyncsRepositoryImpl.java --- a/server/src/main/java/org/iri_research/renkan/repositories/ProjectSyncsRepositoryImpl.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/repositories/ProjectSyncsRepositoryImpl.java Wed Jan 15 18:36:27 2014 +0100 @@ -1,55 +1,52 @@ package org.iri_research.renkan.repositories; -import java.util.Date; - import org.iri_research.renkan.RenkanException; import org.iri_research.renkan.models.Project; import org.iri_research.renkan.models.ProjectSync; +import org.joda.time.DateTime; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component -public class ProjectSyncsRepositoryImpl implements - ProjectSyncsRepositoryCustom { +public class ProjectSyncsRepositoryImpl implements ProjectSyncsRepositoryCustom { + + @Autowired + private ProjectsRepository projectRepository; + + @Override + public ProjectSync getProjectSync(String data, Project project, String user) + throws RenkanException { + + if (project == null) { + throw new RenkanException("ProjectSyncsRepository : Null Project."); + } + + ProjectSync ps = new ProjectSync(null, data, project, + this.projectRepository.getRevCounter(project.getId()), + new DateTime(), user); + + return ps; + } - @Autowired - private ProjectsRepository projectRepository; - - @Override - public ProjectSync getProjectSync(String data, Project project, String user) throws RenkanException { - - if(project == null) { - throw new RenkanException("ProjectSyncsRepository : Null Project."); - } - - ProjectSync ps = new ProjectSync( - null, - data, - project, - this.projectRepository.getRevCounter(project.getId()), - new Date(System.currentTimeMillis()), - user - ); - - return ps; - } + @Override + public ProjectSync getProjectSync(String data, String project_id, + String user) throws RenkanException { + + if (project_id == null || "".equals(project_id)) { + throw new RenkanException( + "ProjectSyncsRepository : Null or empty project id."); + } - @Override - public ProjectSync getProjectSync(String data, String project_id, String user) - throws RenkanException { - - if(project_id == null || "".equals(project_id) ) { - throw new RenkanException("ProjectSyncsRepository : Null or empty project id."); - } - - Project p = this.projectRepository.findOne(project_id); - - if(p == null) { - throw new RenkanException("ProjectSyncsRepository : project not found for id " + project_id); - } - - return this.getProjectSync(data, p, user); - - } + Project p = this.projectRepository.findOne(project_id); + + if (p == null) { + throw new RenkanException( + "ProjectSyncsRepository : project not found for id " + + project_id); + } + + return this.getProjectSync(data, p, user); + + } } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/repositories/ProjectsRepository.java --- a/server/src/main/java/org/iri_research/renkan/repositories/ProjectsRepository.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/repositories/ProjectsRepository.java Wed Jan 15 18:36:27 2014 +0100 @@ -7,13 +7,17 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.mongodb.repository.Query; -public interface ProjectsRepository extends IRenkanRepository, ProjectsRepositoryCustom { - - List findBySpaceId(String spaceId); - Page findBySpaceId(String spaceId, Pageable p); +public interface ProjectsRepository extends IRenkanRepository, + ProjectsRepositoryCustom { + + List findBySpaceId(String spaceId); + + Page findBySpaceId(String spaceId, Pageable p); - @Query("{ 'space_id' : ?0, 'title' : { '$regex':?1, '$options': 'i'} }") - List findBySpaceIdAndTitleRegex(String spaceId, String title); - @Query("{ 'space_id' : ?0, 'title' : { '$regex':?1, '$options': 'i'} }") - Page findBySpaceIdAndTitleRegex(String spaceId, String title, Pageable p); + @Query("{ 'space_id' : ?0, 'title' : { '$regex':?1, '$options': 'i'} }") + List findBySpaceIdAndTitleRegex(String spaceId, String title); + + @Query("{ 'space_id' : ?0, 'title' : { '$regex':?1, '$options': 'i'} }") + Page findBySpaceIdAndTitleRegex(String spaceId, String title, + Pageable p); } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/repositories/ProjectsRepositoryCustom.java --- a/server/src/main/java/org/iri_research/renkan/repositories/ProjectsRepositoryCustom.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/repositories/ProjectsRepositoryCustom.java Wed Jan 15 18:36:27 2014 +0100 @@ -6,15 +6,27 @@ import org.iri_research.renkan.models.Project; public interface ProjectsRepositoryCustom { - - public int getRevCounter(String projectId); - public Map getCountBySpace(); - public Map getCountBySpace(Collection spaceIds); - - public void deleteRecursive(String projectId); - public void deleteRecursive(Project project); - public void deleteRecursive(Iterable projects); - - public Project copy(Project p, String newTitle); - + + public int getRevCounter(String projectId); + + public Map getCountBySpace(); + + public Map getCountBySpace(Collection spaceIds); + + public Map getCountByUser(); + + public Map getCountByUser(Collection userIds); + + public Map getCountByUsername(); + + public Map getCountByUsername(Collection usernames); + + public void deleteRecursive(String projectId); + + public void deleteRecursive(Project project); + + public void deleteRecursive(Iterable projects); + + public Project copy(Project p, String newTitle); + } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/repositories/ProjectsRepositoryImpl.java --- a/server/src/main/java/org/iri_research/renkan/repositories/ProjectsRepositoryImpl.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/repositories/ProjectsRepositoryImpl.java Wed Jan 15 18:36:27 2014 +0100 @@ -1,5 +1,8 @@ package org.iri_research.renkan.repositories; +import static org.springframework.data.mongodb.core.query.Criteria.where; +import static org.springframework.data.mongodb.core.query.Query.query; + import java.util.Arrays; import java.util.Collection; import java.util.HashMap; @@ -7,120 +10,220 @@ import org.iri_research.renkan.models.Project; import org.iri_research.renkan.models.ProjectRevision; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.stereotype.Component; -import static org.springframework.data.mongodb.core.query.Query.query; -import static org.springframework.data.mongodb.core.query.Criteria.where; - import org.springframework.data.mongodb.core.mapreduce.GroupBy; import org.springframework.data.mongodb.core.mapreduce.GroupByResults; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Update; +import org.springframework.stereotype.Component; + +import com.mongodb.AggregationOutput; +import com.mongodb.BasicDBObject; +import com.mongodb.DBObject; @Component public class ProjectsRepositoryImpl implements ProjectsRepositoryCustom { - - @Autowired - private ProjectsRepository projectsRepository; + + @SuppressWarnings("unused") + private final Logger logger = LoggerFactory + .getLogger(ProjectsRepositoryImpl.class); + + @Autowired + private ProjectsRepository projectsRepository; + + @Autowired + private NodesRepository nodesRepository; + + @Autowired + private EdgesRepository edgesRepository; + + @Autowired + private ProjectRevisionsRepository projectRevisionsRepository; + + private class GroupSpaceResult { + public String space_id; + public int count; + } - @Autowired - private NodesRepository nodesRepository; + @Autowired + private MongoTemplate mongoTemplate; + + @Override + public int getRevCounter(String projectId) { + Project p = this.mongoTemplate.findAndModify( + query(where("id").is(projectId)), + new Update().inc("rev_counter", 1), Project.class); - @Autowired - private EdgesRepository edgesRepository; - - @Autowired - private ProjectRevisionsRepository projectRevisionsRepository; + if (p == null) { + return -1; + } + return p.getRevCounter(); + } + + @Override + public Map getCountBySpace(Collection spaceIds) { + + Criteria filter = null; + + if (spaceIds != null) { + filter = Criteria.where("space_id").in(spaceIds); + } - - private class GroupResult { - public String space_id; - public int count; - } - - @Autowired - private MongoTemplate mongoTemplate; - - @Override - public int getRevCounter(String projectId) { - Project p = this.mongoTemplate.findAndModify(query(where("id").is(projectId)), new Update().inc("rev_counter", 1), Project.class); - - if(p == null) { - return -1; - } - return p.getRevCounter(); - } - + GroupByResults groupResult = this.mongoTemplate + .group(filter, + this.mongoTemplate.getCollectionName(Project.class), + GroupBy.key("space_id") + .initialDocument("{ count: 0 }") + .reduceFunction( + "function(doc, prev) { prev.count += 1; }"), + GroupSpaceResult.class); + + HashMap res = new HashMap<>(); + for (GroupSpaceResult gr : groupResult) { + res.put(gr.space_id, new Integer(gr.count)); + } + + return res; + + } + + @Override + public Map getCountBySpace() { + return this.getCountBySpace(null); + } + + @Override + public Project copy(Project p, String newTitle) { - @Override - public Map getCountBySpace(Collection spaceIds) { + Project res = new Project(p); + res.setTitle(newTitle); + this.nodesRepository.save(res.getNodes()); + this.edgesRepository.save(res.getEdges()); + + return this.projectsRepository.save(res); + } + + @Override + public void deleteRecursive(String projectId) { + this.deleteRecursive(this.projectsRepository.findOne(projectId)); + } + + @Override + public void deleteRecursive(Project project) { + this.deleteRecursive(Arrays.asList(new Project[] { project })); + } + + @Override + public void deleteRecursive(Iterable projects) { + + for (Project p : projects) { + if (p == null) { + continue; + } - Criteria filter = null; - - if(spaceIds != null) { - filter = Criteria.where("space_id").in(spaceIds); - } - - GroupByResults groupResult = this.mongoTemplate.group( - filter, - this.mongoTemplate.getCollectionName(Project.class), - GroupBy.key("space_id").initialDocument("{ count: 0 }").reduceFunction("function(doc, prev) { prev.count += 1; }"), - GroupResult.class); - - HashMap res = new HashMap<>(); - for (GroupResult gr : groupResult) { - res.put(gr.space_id, new Integer(gr.count)); - } - - return res; - - } - - @Override - public Map getCountBySpace() { - return this.getCountBySpace(null); - } + ProjectRevision pr = this.projectRevisionsRepository + .getProjectRevision(p, + this.projectsRepository.getRevCounter(p.getId())); + this.projectRevisionsRepository.save(pr); + + // delete edges + this.edgesRepository.delete(p.getEdges()); + // delete nodes + this.nodesRepository.delete(p.getNodes()); + // delete project + this.projectsRepository.delete(p); + } + } + + @Override + public Map getCountByUser() { + return getCountByUser(null); + } + + @Override + public Map getCountByUser(Collection userIds) { + + Criteria filter = null; + if (userIds != null) { + filter = Criteria.where("users.user_id").in(userIds); + } + + DBObject projectOp = new BasicDBObject("$project", new BasicDBObject( + "users", 1)); + DBObject unwindOp = new BasicDBObject("$unwind", "$users"); + DBObject groupOpFields = new BasicDBObject("_id", "$users.user_id"); + groupOpFields.put("count", new BasicDBObject("$sum", 1)); + DBObject groupOp = new BasicDBObject("$group", groupOpFields); + DBObject matchOp = null; + if (filter != null) { + matchOp = new BasicDBObject("$match", filter.getCriteriaObject()); + } + + AggregationOutput output = null; + if (filter != null) { + output = this.projectsRepository.getCollection().aggregate(matchOp, + projectOp, unwindOp, matchOp, groupOp); + } else { + output = this.projectsRepository.getCollection().aggregate( + projectOp, unwindOp, groupOp); + } + + HashMap res = new HashMap<>(); - @Override - public Project copy(Project p, String newTitle) { - - Project res = new Project(p); - res.setTitle(newTitle); - this.nodesRepository.save(res.getNodes()); - this.edgesRepository.save(res.getEdges()); - - return this.projectsRepository.save(res); - } + for (DBObject groupRes : output.results()) { + res.put((String) groupRes.get("_id"), + (Integer) groupRes.get("count")); + } + + return res; + } - @Override - public void deleteRecursive(String projectId) { - this.deleteRecursive(this.projectsRepository.findOne(projectId)); - } + @Override + public Map getCountByUsername() { + return this.getCountByUsername(null); + } - @Override - public void deleteRecursive(Project project) { - this.deleteRecursive(Arrays.asList(new Project[] {project})); - } + @Override + public Map getCountByUsername(Collection usernames) { + + Criteria filter = null; + + if (usernames != null) { + filter = Criteria.where("users.username").in(usernames); + } - @Override - public void deleteRecursive(Iterable projects) { - - for(Project p: projects) { - if( p == null) { - continue; - } - - ProjectRevision pr = this.projectRevisionsRepository.getProjectRevision(p, this.projectsRepository.getRevCounter(p.getId())); - this.projectRevisionsRepository.save(pr); - - //delete edges - this.edgesRepository.delete(p.getEdges()); - //delete nodes - this.nodesRepository.delete(p.getNodes()); - //delete project - this.projectsRepository.delete(p); - } - } + DBObject projectOp = new BasicDBObject("$project", new BasicDBObject( + "users", 1)); + DBObject unwindOp = new BasicDBObject("$unwind", "$users"); + DBObject groupOpFields = new BasicDBObject("_id", "$users.username"); + groupOpFields.put("count", new BasicDBObject("$sum", 1)); + DBObject groupOp = new BasicDBObject("$group", groupOpFields); + DBObject matchOp = null; + if (filter != null) { + matchOp = new BasicDBObject("$match", filter.getCriteriaObject()); + } + + AggregationOutput output = null; + if (filter != null) { + output = this.projectsRepository.getCollection().aggregate(matchOp, + projectOp, unwindOp, matchOp, groupOp); + } else { + output = this.projectsRepository.getCollection().aggregate( + projectOp, unwindOp, groupOp); + } + + HashMap res = new HashMap<>(); + + for (DBObject groupRes : output.results()) { + res.put((String) groupRes.get("_id"), + (Integer) groupRes.get("count")); + } + + return res; + + } } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/repositories/RenkanRepository.java --- a/server/src/main/java/org/iri_research/renkan/repositories/RenkanRepository.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/repositories/RenkanRepository.java Wed Jan 15 18:36:27 2014 +0100 @@ -8,16 +8,17 @@ import com.mongodb.DBCollection; -public class RenkanRepository extends SimpleMongoRepository implements - IRenkanRepository { +public class RenkanRepository extends + SimpleMongoRepository implements IRenkanRepository { - public RenkanRepository(MongoEntityInformation metadata, - MongoOperations mongoOperations) { - super(metadata, mongoOperations); - } + public RenkanRepository(MongoEntityInformation metadata, + MongoOperations mongoOperations) { + super(metadata, mongoOperations); + } - @Override - public DBCollection getCollection() { - return this.getMongoOperations().getCollection(this.getEntityInformation().getCollectionName()); - } + @Override + public DBCollection getCollection() { + return this.getMongoOperations().getCollection( + this.getEntityInformation().getCollectionName()); + } } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/repositories/RenkanRepositoryException.java --- a/server/src/main/java/org/iri_research/renkan/repositories/RenkanRepositoryException.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/repositories/RenkanRepositoryException.java Wed Jan 15 18:36:27 2014 +0100 @@ -2,10 +2,10 @@ public class RenkanRepositoryException extends Exception { - private static final long serialVersionUID = -7433823426870169568L; - - public RenkanRepositoryException(String message) { - super(message); - } + private static final long serialVersionUID = -7433823426870169568L; + + public RenkanRepositoryException(String message) { + super(message); + } } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/repositories/RenkanRepositoryFactory.java --- a/server/src/main/java/org/iri_research/renkan/repositories/RenkanRepositoryFactory.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/repositories/RenkanRepositoryFactory.java Wed Jan 15 18:36:27 2014 +0100 @@ -10,41 +10,45 @@ public class RenkanRepositoryFactory extends MongoRepositoryFactory { - private MongoOperations mongoOperations; - public RenkanRepositoryFactory(MongoOperations mongoOperations) { - super(mongoOperations); - this.mongoOperations = mongoOperations; - } + private MongoOperations mongoOperations; + + public RenkanRepositoryFactory(MongoOperations mongoOperations) { + super(mongoOperations); + this.mongoOperations = mongoOperations; + } + + /* + * (non-Javadoc) + * + * @see + * org.springframework.data.repository.core.support.RepositoryFactorySupport + * #getTargetRepository(org.springframework.data.repository.core. + * RepositoryMetadata) + */ + @Override + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected Object getTargetRepository(RepositoryMetadata metadata) { + + Object res = super.getTargetRepository(metadata); - /* - * (non-Javadoc) - * @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getTargetRepository(org.springframework.data.repository.core.RepositoryMetadata) - */ - @Override - @SuppressWarnings({ "rawtypes", "unchecked" }) - protected Object getTargetRepository(RepositoryMetadata metadata) { - - Object res = super.getTargetRepository(metadata); - - if(SimpleMongoRepository.class.equals(res.getClass())) { - MongoEntityInformation entityInformation = this.getEntityInformation(metadata.getDomainType()); - return new RenkanRepository(entityInformation, this.mongoOperations); - } - else { - return res; - } + if (SimpleMongoRepository.class.equals(res.getClass())) { + MongoEntityInformation entityInformation = this + .getEntityInformation(metadata.getDomainType()); + return new RenkanRepository(entityInformation, this.mongoOperations); + } else { + return res; + } + + } - } - - @Override - protected Class getRepositoryBaseClass(RepositoryMetadata metadata) { - Class res = super.getRepositoryBaseClass(metadata); - if(SimpleMongoRepository.class.equals(res)) { - return RenkanRepository.class; - } - else { - return res; - } - } - + @Override + protected Class getRepositoryBaseClass(RepositoryMetadata metadata) { + Class res = super.getRepositoryBaseClass(metadata); + if (SimpleMongoRepository.class.equals(res)) { + return RenkanRepository.class; + } else { + return res; + } + } + } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/repositories/RenkanRepositoryFactoryBean.java --- a/server/src/main/java/org/iri_research/renkan/repositories/RenkanRepositoryFactoryBean.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/repositories/RenkanRepositoryFactoryBean.java Wed Jan 15 18:36:27 2014 +0100 @@ -7,11 +7,13 @@ import org.springframework.data.repository.Repository; import org.springframework.data.repository.core.support.RepositoryFactorySupport; -public class RenkanRepositoryFactoryBean,S,ID extends Serializable> extends MongoRepositoryFactoryBean { - - @Override - protected RepositoryFactorySupport getFactoryInstance(MongoOperations operations) { - return new RenkanRepositoryFactory(operations); - } - +public class RenkanRepositoryFactoryBean, S, ID extends Serializable> + extends MongoRepositoryFactoryBean { + + @Override + protected RepositoryFactorySupport getFactoryInstance( + MongoOperations operations) { + return new RenkanRepositoryFactory(operations); + } + } \ No newline at end of file diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/repositories/UsersRepository.java --- a/server/src/main/java/org/iri_research/renkan/repositories/UsersRepository.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/repositories/UsersRepository.java Wed Jan 15 18:36:27 2014 +0100 @@ -1,7 +1,15 @@ package org.iri_research.renkan.repositories; +import java.util.List; + import org.iri_research.renkan.models.User; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; -public interface UsersRepository extends IRenkanRepository { +public interface UsersRepository extends IRenkanRepository, UsersRepositoryCustom { + + public List findByTitle(String title); + + public Page findByTitle(String title, Pageable p); } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/repositories/UsersRepositoryCustom.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/java/org/iri_research/renkan/repositories/UsersRepositoryCustom.java Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,17 @@ +package org.iri_research.renkan.repositories; + +import java.util.Collection; +import java.util.Map; + +import org.iri_research.renkan.models.Group; +import org.iri_research.renkan.models.User; + +public interface UsersRepositoryCustom { + /** + * Set the users group list. + * @param user : the user + * @param groupIds : the list of group ids. this parameter must not be null. + */ + public void setGroupsList(User user, Collection groupIds); + public Map getGroupsMap(User user); +} diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/repositories/UsersRepositoryImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/java/org/iri_research/renkan/repositories/UsersRepositoryImpl.java Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,66 @@ +package org.iri_research.renkan.repositories; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.collections4.IteratorUtils; +import org.iri_research.renkan.models.Group; +import org.iri_research.renkan.models.User; +import org.springframework.beans.factory.annotation.Autowired; + +public class UsersRepositoryImpl implements UsersRepositoryCustom { + + @Autowired + private UsersRepository usersRepository; + + @Autowired + private GroupsRepository groupsRepository; + + @Override + // TODO: implement a transaction mecanism... + public void setGroupsList(User user, Collection groupIds) { + + assert groupIds != null : "list of group ids must not be null"; + + // takes previous user list + List oldGroups = new ArrayList<>(user.getGroups()); + + // calculate difference between two list + List groupIdDel = new ArrayList<>(oldGroups); + groupIdDel.removeAll(groupIds); + + List groupIdAdd = new ArrayList<>(groupIds); + groupIdAdd.removeAll(oldGroups); + + List groupAdd = IteratorUtils.toList(this.groupsRepository.findAll(groupIdAdd).iterator()); + for (Group group : groupAdd) { + group.addUser(user); + } + this.groupsRepository.save(groupAdd); + List groupDel = IteratorUtils.toList(this.groupsRepository.findAll(groupIdDel).iterator()); + for (Group group : groupDel) { + group.removeUser(user); + } + this.groupsRepository.save(groupDel); + + user.getGroups().clear(); + user.getGroups().addAll(groupIds); + + this.usersRepository.save(user); + } + + @Override + public Map getGroupsMap(User user) { + HashMap res = new HashMap<>(user.getGroups().size()); + + for (Group group : this.groupsRepository.findAll(user.getGroups())) { + res.put(group.getId(), group); + } + + return res; + } + +} diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/rest/ObjectMapperProvider.java --- a/server/src/main/java/org/iri_research/renkan/rest/ObjectMapperProvider.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/rest/ObjectMapperProvider.java Wed Jan 15 18:36:27 2014 +0100 @@ -7,17 +7,20 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.joda.JodaModule; @Component @Provider public class ObjectMapperProvider implements ContextResolver { - @Override - public ObjectMapper getContext(Class type) { - ObjectMapper objectMapper = new ObjectMapper(); - objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); - - return objectMapper; - } + @Override + public ObjectMapper getContext(Class type) { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, + false); + objectMapper.registerModule(new JodaModule()); + + return objectMapper; + } } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/rest/ProjectsResource.java --- a/server/src/main/java/org/iri_research/renkan/rest/ProjectsResource.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/rest/ProjectsResource.java Wed Jan 15 18:36:27 2014 +0100 @@ -1,60 +1,58 @@ package org.iri_research.renkan.rest; import java.util.Arrays; -import java.util.Date; import java.util.List; +import javax.inject.Singleton; import javax.ws.rs.Path; import org.iri_research.renkan.Constants; import org.iri_research.renkan.models.Project; import org.iri_research.renkan.repositories.IRenkanRepository; import org.iri_research.renkan.repositories.ProjectsRepository; +import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import com.sun.jersey.spi.resource.Singleton; - - @Singleton @Path("projects") @Component public class ProjectsResource extends RenkanResource { - - @SuppressWarnings("unused") - private Logger logger = LoggerFactory.getLogger(ProjectsResource.class); - - @Autowired - private ProjectsRepository projectsRepository; + + @SuppressWarnings("unused") + private Logger logger = LoggerFactory.getLogger(ProjectsResource.class); + + @Autowired + private ProjectsRepository projectsRepository; - @Override - protected IRenkanRepository getRepository() { - return this.projectsRepository; - } + @Override + protected IRenkanRepository getRepository() { + return this.projectsRepository; + } - @Override - protected String getNewId() { - return Constants.UUID_GENERATOR.generate().toString(); - } + @Override + protected String getNewId() { + return Constants.UUID_GENERATOR.generate().toString(); + } - @Override - protected void prepareObject(Project obj) { - if(obj.getCreated() == null) { - obj.setCreated(new Date()); - } - obj.setUpdated(new Date()); - } + @Override + protected void prepareObject(Project obj) { + if (obj.getCreated() == null) { + obj.setCreated(new DateTime()); + } + obj.setUpdated(new DateTime()); + } - @Override - protected List getObjectListFieldList() { - return Arrays.asList(this.baseObjectListFieldList); - } - - @Override - protected void doDeleteObject(String objectId) { - this.projectsRepository.deleteRecursive(objectId); - } + @Override + protected List getObjectListFieldList() { + return Arrays.asList(this.baseObjectListFieldList); + } + + @Override + protected void doDeleteObject(String objectId) { + this.projectsRepository.deleteRecursive(objectId); + } } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/rest/RenkanResource.java --- a/server/src/main/java/org/iri_research/renkan/rest/RenkanResource.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/rest/RenkanResource.java Wed Jan 15 18:36:27 2014 +0100 @@ -6,14 +6,12 @@ import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; -import javax.ws.rs.DefaultValue; 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.Context; import javax.ws.rs.core.MediaType; @@ -21,6 +19,7 @@ import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.UriInfo; +import org.glassfish.jersey.server.JSONP; import org.iri_research.renkan.models.IRenkanModel; import org.iri_research.renkan.repositories.IRenkanRepository; import org.slf4j.Logger; @@ -29,155 +28,186 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.joda.JodaModule; import com.mongodb.BasicDBObject; import com.mongodb.DBCollection; import com.mongodb.DBCursor; import com.mongodb.DBObject; -import com.sun.jersey.api.json.JSONWithPadding; public abstract class RenkanResource, ID extends Serializable> { - - private Logger logger = LoggerFactory.getLogger(RenkanResource.class); - - protected String[] baseObjectListFieldList = {"description","title","uri","created", "color"}; + + private Logger logger = LoggerFactory.getLogger(RenkanResource.class); + + protected String[] baseObjectListFieldList = { "description", "title", + "uri", "created", "color" }; + + abstract protected IRenkanRepository getRepository(); + + abstract protected ID getNewId(); + + abstract protected List getObjectListFieldList(); + + @Context + private UriInfo uriInfo; + + protected DBCollection getCollection() { + return this.getRepository().getCollection(); + } - abstract protected IRenkanRepository getRepository(); - abstract protected ID getNewId(); - abstract protected List getObjectListFieldList(); + abstract protected void prepareObject(T obj); + + protected void doDeleteObject(ID objectId) { + this.getRepository().delete(objectId); + } - @Context - private UriInfo uriInfo; + // TODO: this produce application/javascript by default. I would rather have + // application/json. The prefered behaviour would be to produde js only od + // the callbacl query param is used + @GET + @Path("{id : [a-zA-Z\\-0-9]+}") + @JSONP(callback = "callback", queryParam = "callback") + @Produces({ "application/javascript", "application/x-javascript", + "text/ecmascript", "application/ecmascript", "text/jscript", + MediaType.APPLICATION_JSON + ";charset=utf-8" }) + public T getObject(@PathParam("id") ID objectId) { + + this.logger.debug("GetObject: " + objectId); + + T obj = this.getRepository().findOne(objectId); - protected DBCollection getCollection() { - return this.getRepository().getCollection(); - } - - abstract protected void prepareObject(T obj); - - protected void doDeleteObject(ID objectId) { - this.getRepository().delete(objectId); - } - - - //TODO: this produce application/javascript by default. I would rather have application/json. The prefered behaviour would be to produde js only od the callbacl query param is used - @GET - @Path("{id : [a-zA-Z\\-0-9]+}") - @Produces({ "application/javascript", - "application/x-javascript", "text/ecmascript", - "application/ecmascript", "text/jscript", MediaType.APPLICATION_JSON + ";charset=utf-8"}) - public JSONWithPadding getObject(@PathParam("id") ID objectId, @QueryParam("callback") @DefaultValue("callback") String callback) { - - this.logger.debug("GetObject: " + objectId); - - T obj = this.getRepository().findOne(objectId); - - if (null == obj) { - throw new WebApplicationException(Status.NOT_FOUND); - } - - return new JSONWithPadding(obj, callback); - } - - @DELETE - @Path("{id : [a-zA-Z\\-0-9]+}") - @Produces(MediaType.TEXT_PLAIN + ";charset=utf-8") - public Response deleteObject(@PathParam("id") ID objectId) { - - this.logger.debug("DeleteObject : id " + objectId); - this.doDeleteObject(objectId); - - return Response.ok(this.uriInfo.getAbsolutePathBuilder().build().toString() + " deleted").build(); - - } - - /** - * test: curl -i -X PUT -H 'Content-Type: application/json' -d @test-data.json http://localhost:8080/renkan/rest/spaces/12eff140-e65c-11e1-aff1-0800200c9a66 - * @param objId - * @param objectContent - */ - @PUT - @Path("{id : [a-zA-Z\\-0-9]+}") - @Consumes(MediaType.APPLICATION_JSON + ";charset=utf-8") - public Response putRenkanObject(@PathParam("id") ID objId, T obj) { + if (null == obj) { + throw new WebApplicationException(Status.NOT_FOUND); + } + + return obj; + } + + @DELETE + @Path("{id : [a-zA-Z\\-0-9]+}") + @Produces(MediaType.TEXT_PLAIN + ";charset=utf-8") + public Response deleteObject(@PathParam("id") ID objectId) { + + this.logger.debug("DeleteObject : id " + objectId); + this.doDeleteObject(objectId); + + return Response.ok( + this.uriInfo.getAbsolutePathBuilder().build().toString() + + " deleted").build(); + + } + + /** + * test: curl -i -X PUT -H 'Content-Type: application/json' -d + * + * @test-data.json http://localhost:8080/renkan/rest/spaces/ + * 12eff140-e65c-11e1-aff1-0800200c9a66 + * + * @param objId + * @param objectContent + */ + @PUT + @Path("{id : [a-zA-Z\\-0-9]+}") + @Consumes(MediaType.APPLICATION_JSON + ";charset=utf-8") + public Response putRenkanObject(@PathParam("id") ID objId, T obj) { + + if (!objId.equals(obj.getId())) { + throw new WebApplicationException(Response + .status(Status.BAD_REQUEST) + .entity("Id parameter and id in JSON do not match").build()); + } + + if (!this.getRepository().exists(objId)) { + throw new WebApplicationException(Response.status(Status.NOT_FOUND) + .build()); + } - if(!objId.equals(obj.getId())) { - throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("Id parameter and id in JSON do not match").build()); - } - - if(!this.getRepository().exists(objId)) { - throw new WebApplicationException(Response.status(Status.NOT_FOUND).build()); - } - - this.prepareObject(obj); - this.getRepository().save(obj); - return Response.noContent().build(); - - } - - @POST - @Consumes(MediaType.APPLICATION_JSON + ";charset=utf-8") - @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8") - public Response postRenkanObject(T obj) { + this.prepareObject(obj); + this.getRepository().save(obj); + return Response.noContent().build(); + + } + + @POST + @Consumes(MediaType.APPLICATION_JSON + ";charset=utf-8") + @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8") + public Response postRenkanObject(T obj) { + + if (obj.getId() != null) { + throw new WebApplicationException(Response + .status(Status.BAD_REQUEST) + .entity("Id in JSON must be null").build()); + } - if(obj.getId() != null) { - throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("Id in JSON must be null").build()); - } - - obj.setId(getNewId()); - this.prepareObject(obj); - obj = this.getRepository().save(obj); - return Response.created(this.uriInfo.getAbsolutePathBuilder().segment(obj.getId().toString()).build()).entity(obj).build(); - } - + obj.setId(getNewId()); + this.prepareObject(obj); + obj = this.getRepository().save(obj); + return Response + .created( + this.uriInfo.getAbsolutePathBuilder() + .segment(obj.getId().toString()).build()) + .entity(obj).build(); + } + + @GET + @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8") + public String getObjectList() throws JsonProcessingException { + + BasicDBObject keys = new BasicDBObject(); + + for (String fieldname : this.getObjectListFieldList()) { + keys.put(fieldname, 1); + } + DBCursor cursor = this.getCollection().find(new BasicDBObject(), keys); + + List res = new ArrayList(); - @GET - @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8") - public String getObjectList() throws JsonProcessingException { - - BasicDBObject keys = new BasicDBObject(); - - for (String fieldname : this.getObjectListFieldList()) { - keys.put(fieldname, 1); - } - DBCursor cursor = this.getCollection().find(new BasicDBObject(), keys); - - List res = new ArrayList(); - - try { - while(cursor.hasNext()) { - DBObject obj = cursor.next(); - obj.put("id", obj.get("_id")); - DBObject links = new BasicDBObject(); - - DBObject linkdef = new BasicDBObject(); - linkdef.put("href", this.uriInfo.getAbsolutePathBuilder().path(obj.get("_id").toString()).build().toString()); - linkdef.put("method", "get"); - linkdef.put("produces", MediaType.APPLICATION_JSON + ";charset=utf-8"); - links.put("view", linkdef); - - linkdef = new BasicDBObject(); - linkdef.put("href", this.uriInfo.getAbsolutePathBuilder().path(obj.get("_id").toString()).build().toString()); - linkdef.put("method", "put"); - linkdef.put("consumes", MediaType.APPLICATION_JSON + ";charset=utf-8"); - links.put("update", linkdef); + try { + while (cursor.hasNext()) { + DBObject obj = cursor.next(); + obj.put("id", obj.get("_id")); + DBObject links = new BasicDBObject(); + + DBObject linkdef = new BasicDBObject(); + linkdef.put( + "href", + this.uriInfo.getAbsolutePathBuilder() + .path(obj.get("_id").toString()).build() + .toString()); + linkdef.put("method", "get"); + linkdef.put("produces", MediaType.APPLICATION_JSON + + ";charset=utf-8"); + links.put("view", linkdef); - linkdef = new BasicDBObject(); - linkdef.put("href", this.uriInfo.getAbsolutePathBuilder().path(obj.get("_id").toString()).build().toString()); - linkdef.put("method", "delete"); - links.put("delete", linkdef); - - obj.put("__links", links); - res.add(obj); - } - } - finally { - cursor.close(); - } - ObjectMapper mapper = new ObjectMapper(); - mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); - return mapper.writeValueAsString(res); - } + linkdef = new BasicDBObject(); + linkdef.put( + "href", + this.uriInfo.getAbsolutePathBuilder() + .path(obj.get("_id").toString()).build() + .toString()); + linkdef.put("method", "put"); + linkdef.put("consumes", MediaType.APPLICATION_JSON + + ";charset=utf-8"); + links.put("update", linkdef); + linkdef = new BasicDBObject(); + linkdef.put( + "href", + this.uriInfo.getAbsolutePathBuilder() + .path(obj.get("_id").toString()).build() + .toString()); + linkdef.put("method", "delete"); + links.put("delete", linkdef); - + obj.put("__links", links); + res.add(obj); + } + } finally { + cursor.close(); + } + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + mapper.registerModule(new JodaModule()); + return mapper.writeValueAsString(res); + } + } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/rest/RestApplication.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/java/org/iri_research/renkan/rest/RestApplication.java Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,28 @@ +package org.iri_research.renkan.rest; + +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.spring.SpringLifecycleListener; +import org.glassfish.jersey.server.spring.scope.RequestContextFilter; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.joda.JodaModule; +import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; + +public class RestApplication extends ResourceConfig { + public RestApplication() { + + this.packages("org.iri_research.renkan.rest"); + this.register(SpringLifecycleListener.class); + this.register(RequestContextFilter.class); + + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, + false); + objectMapper.registerModule(new JodaModule()); + JacksonJaxbJsonProvider provider = new JacksonJaxbJsonProvider(objectMapper, JacksonJaxbJsonProvider.DEFAULT_ANNOTATIONS); + + this.register(provider); + + } +} diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/rest/SpacesResource.java --- a/server/src/main/java/org/iri_research/renkan/rest/SpacesResource.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/rest/SpacesResource.java Wed Jan 15 18:36:27 2014 +0100 @@ -1,64 +1,61 @@ package org.iri_research.renkan.rest; - import java.util.ArrayList; import java.util.Arrays; -import java.util.Date; import java.util.List; +import javax.inject.Singleton; import javax.ws.rs.Path; import org.iri_research.renkan.Constants; import org.iri_research.renkan.models.Space; import org.iri_research.renkan.repositories.IRenkanRepository; import org.iri_research.renkan.repositories.SpacesRepository; +import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import com.sun.jersey.spi.resource.Singleton; - @Singleton @Path("spaces") @Component public class SpacesResource extends RenkanResource { - - @SuppressWarnings("unused") - private Logger logger = LoggerFactory.getLogger(SpacesResource.class); - - private String[] spaceObjectListFieldList = {"created_by","bin_config","image"}; - - @Autowired - private SpacesRepository spacesRepository; - - @Override - protected IRenkanRepository getRepository() { - return spacesRepository; - } + + @SuppressWarnings("unused") + private Logger logger = LoggerFactory.getLogger(SpacesResource.class); + + private String[] spaceObjectListFieldList = { "created_by", "bin_config", + "image" }; + @Autowired + private SpacesRepository spacesRepository; + + @Override + protected IRenkanRepository getRepository() { + return spacesRepository; + } - @Override - protected String getNewId() { - return Constants.UUID_GENERATOR.generate().toString(); - } - + @Override + protected String getNewId() { + return Constants.UUID_GENERATOR.generate().toString(); + } - @Override - protected void prepareObject(Space obj) { - if(obj.getCreated() == null) { - obj.setCreated(new Date()); - } - } - + @Override + protected void prepareObject(Space obj) { + if (obj.getCreated() == null) { + obj.setCreated(new DateTime()); + } + } - @Override - protected List getObjectListFieldList() { - ArrayList fieldList = new ArrayList<>(this.baseObjectListFieldList.length + this.spaceObjectListFieldList.length); - fieldList.addAll(Arrays.asList(this.baseObjectListFieldList)); - fieldList.addAll(Arrays.asList(this.spaceObjectListFieldList)); - return fieldList; - } - + @Override + protected List getObjectListFieldList() { + ArrayList fieldList = new ArrayList<>( + this.baseObjectListFieldList.length + + this.spaceObjectListFieldList.length); + fieldList.addAll(Arrays.asList(this.baseObjectListFieldList)); + fieldList.addAll(Arrays.asList(this.spaceObjectListFieldList)); + return fieldList; + } } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/services/RenkanUserDetailsService.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/java/org/iri_research/renkan/services/RenkanUserDetailsService.java Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,30 @@ +package org.iri_research.renkan.services; + +import java.util.List; + +import org.iri_research.renkan.models.User; +import org.iri_research.renkan.repositories.UsersRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +@Service +public class RenkanUserDetailsService implements UserDetailsService { + + @Autowired + private UsersRepository usersRepository; + + @Override + public UserDetails loadUserByUsername(String username) + throws UsernameNotFoundException { + List res = this.usersRepository.findByTitle(username); + if (res == null || res.size() == 0) { + throw new UsernameNotFoundException(String.format( + "User {0} not found.", username)); + } + return res.get(0); + } + +} diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/utils/ColorGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/java/org/iri_research/renkan/utils/ColorGenerator.java Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,24 @@ +package org.iri_research.renkan.utils; + +import java.awt.Color; +import java.util.Random; + +public class ColorGenerator { + + public static Color randomColor() { + + Random rand = new Random(); + + float r = rand.nextFloat() * 0.5f + 0.5f; + float g = rand.nextFloat() * 0.5f + 0.5f; + float b = rand.nextFloat() * 0.5f + 0.5f; + + return new Color(r, g, b); + } + + public static String randomColorHex() { + Color resColor = ColorGenerator.randomColor(); + return Integer.toHexString(resColor.getRGB()); + } + +} diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/utils/RenkanLogger.java --- a/server/src/main/java/org/iri_research/renkan/utils/RenkanLogger.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/utils/RenkanLogger.java Wed Jan 15 18:36:27 2014 +0100 @@ -7,9 +7,9 @@ import java.lang.annotation.Retention; import java.lang.annotation.Target; -@Retention(RUNTIME) -@Target(FIELD) -@Documented +@Retention(RUNTIME) +@Target(FIELD) +@Documented public @interface RenkanLogger { } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/java/org/iri_research/renkan/utils/RenkanLoggerInjector.java --- a/server/src/main/java/org/iri_research/renkan/utils/RenkanLoggerInjector.java Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/java/org/iri_research/renkan/utils/RenkanLoggerInjector.java Wed Jan 15 18:36:27 2014 +0100 @@ -7,33 +7,32 @@ import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.stereotype.Component; import org.springframework.util.ReflectionUtils; - -import static org.springframework.util.ReflectionUtils.FieldCallback; +import org.springframework.util.ReflectionUtils.FieldCallback; @Component public class RenkanLoggerInjector implements BeanPostProcessor { - @Override - public Object postProcessBeforeInitialization(final Object bean, - String beanName) throws BeansException { - ReflectionUtils.doWithFields(bean.getClass(), new FieldCallback() { - public void doWith(Field field) throws IllegalArgumentException, - IllegalAccessException { - // make the field accessible if defined private - ReflectionUtils.makeAccessible(field); - if (field.getAnnotation(RenkanLogger.class) != null) { - org.slf4j.Logger logger = LoggerFactory.getLogger(bean - .getClass()); - field.set(bean, logger); - } - } - }); - return bean; - } + @Override + public Object postProcessBeforeInitialization(final Object bean, + String beanName) throws BeansException { + ReflectionUtils.doWithFields(bean.getClass(), new FieldCallback() { + public void doWith(Field field) throws IllegalArgumentException, + IllegalAccessException { + // make the field accessible if defined private + ReflectionUtils.makeAccessible(field); + if (field.getAnnotation(RenkanLogger.class) != null) { + org.slf4j.Logger logger = LoggerFactory.getLogger(bean + .getClass()); + field.set(bean, logger); + } + } + }); + return bean; + } - @Override - public Object postProcessAfterInitialization(Object bean, String beanName) - throws BeansException { - return bean; - } + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + return bean; + } } \ No newline at end of file diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/applicationContext.xml --- a/server/src/main/webapp/WEB-INF/applicationContext.xml Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/webapp/WEB-INF/applicationContext.xml Wed Jan 15 18:36:27 2014 +0100 @@ -51,7 +51,7 @@ - + @@ -68,7 +68,7 @@ For example @Controller and @Service. Make sure to set the correct base-package--> - + + \ No newline at end of file diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/spring-servlet.xml --- a/server/src/main/webapp/WEB-INF/spring-servlet.xml Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/webapp/WEB-INF/spring-servlet.xml Wed Jan 15 18:36:27 2014 +0100 @@ -67,6 +67,4 @@ - - \ No newline at end of file diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/templates/admin/adminIndex.html --- a/server/src/main/webapp/WEB-INF/templates/admin/adminIndex.html Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/webapp/WEB-INF/templates/admin/adminIndex.html Wed Jan 15 18:36:27 2014 +0100 @@ -1,5 +1,5 @@ - + Renkan Admin @@ -32,11 +32,17 @@ Spaces + + Users + + + Groups +
-
© 2013 IRI - Version 0.0
+
© 2013 IRI - Version 0.0
diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/templates/admin/groupDeleteConfirm.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/webapp/WEB-INF/templates/admin/groupDeleteConfirm.html Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,35 @@ + + + + Renkan Admin - delete group + + + + + + + + + + + + + +
+
+ +

Groups List / Delete group

+
+
Do you want to Delete group with name
+
+
+
+
+
© 2013 IRI - Version 0.0
+
+
+ + \ No newline at end of file diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/templates/admin/groupEdit.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/webapp/WEB-INF/templates/admin/groupEdit.html Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,39 @@ + + + + Renkan Admin - edit user + + + + + + + + + + + + + + + + + + + +
+
+ +

Groups List / Edit group

+
+
+
+
+
© 2013 IRI - Version 0.0
+
+
+ + \ No newline at end of file diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/templates/admin/groupsList.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/webapp/WEB-INF/templates/admin/groupsList.html Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,68 @@ + + + + Renkan Admin - Groups + + + + + + + + + + + + + +
+
+ +

List of objects

+
+
+ << + < + ... + 2 + 3 + 4 + 5 + 6 + ... + > + >> +
+
+
+ + + + + + + + + + + + + + + + +
GroupnameEditDelete
groupnameEditDelete
+
+ +
+
+
© 2013 IRI - Version 0.0
+
+
+ + \ No newline at end of file diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/templates/admin/spaceDeleteConfirm.html --- a/server/src/main/webapp/WEB-INF/templates/admin/spaceDeleteConfirm.html Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/webapp/WEB-INF/templates/admin/spaceDeleteConfirm.html Wed Jan 15 18:36:27 2014 +0100 @@ -1,7 +1,7 @@ - + - Renkan Admin - edit space + Renkan Admin - delete space @@ -22,13 +22,13 @@

Spaces List / Delete space

-
-
Do you want to delete space with title
-
+
+
Do you want to delete space with title
+
-
© 2013 IRI - Version 0.0
+
© 2013 IRI - Version 0.0
diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/templates/admin/spaceEdit.html --- a/server/src/main/webapp/WEB-INF/templates/admin/spaceEdit.html Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/webapp/WEB-INF/templates/admin/spaceEdit.html Wed Jan 15 18:36:27 2014 +0100 @@ -1,5 +1,5 @@ - + Renkan Admin - edit space @@ -13,9 +13,10 @@ - + + @@ -30,7 +31,7 @@
-
© 2013 IRI - Version 0.0
+
© 2013 IRI - Version 0.0
diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/templates/admin/spacesList.html --- a/server/src/main/webapp/WEB-INF/templates/admin/spacesList.html Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/webapp/WEB-INF/templates/admin/spacesList.html Wed Jan 15 18:36:27 2014 +0100 @@ -1,5 +1,5 @@ - + Renkan Admin - Spaces @@ -21,10 +21,10 @@

Renkan administration

-

List of objects

+

List of objects

- << + << < ... 2 @@ -39,27 +39,27 @@
- - - - - - + + + + + + - - - - - - + + + + + +
NameCreatedProject counturlEditDeleteNameCreatedProject counturlEditDelete
titlecreatednb. projurlEditDeleteDeletetitlecreatednb. projurlEditDeleteDelete
@@ -67,7 +67,7 @@
-
© 2013 IRI - Version 0.0
+
© 2013 IRI - Version 0.0
diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/templates/admin/userDeleteConfirm.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/webapp/WEB-INF/templates/admin/userDeleteConfirm.html Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,35 @@ + + + + Renkan Admin - delete user + + + + + + + + + + + + + +
+
+ +

Users List / Delete user

+
+
Do you want to Delete user with name
+
+
+
+
+
© 2013 IRI - Version 0.0
+
+
+ + \ No newline at end of file diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/templates/admin/userEdit.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/webapp/WEB-INF/templates/admin/userEdit.html Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,39 @@ + + + + Renkan Admin - edit user + + + + + + + + + + + + + + + + + + + +
+
+ +

Users List / Edit user

+
+
+
+
+
© 2013 IRI - Version 0.0
+
+
+ + \ No newline at end of file diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/templates/admin/usersList.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/webapp/WEB-INF/templates/admin/usersList.html Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,70 @@ + + + + Renkan Admin - Users + + + + + + + + + + + + + +
+
+ +

List of objects

+
+
+ << + < + ... + 2 + 3 + 4 + 5 + 6 + ... + > + >> +
+
+
+ + + + + + + + + + + + + + + + + + +
UsernameProject countEditDelete
usernamenb. projEditDeleteDelete
+
+ +
+
+
© 2013 IRI - Version 0.0
+
+
+ + \ No newline at end of file diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/templates/auth/login.html --- a/server/src/main/webapp/WEB-INF/templates/auth/login.html Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/webapp/WEB-INF/templates/auth/login.html Wed Jan 15 18:36:27 2014 +0100 @@ -1,5 +1,5 @@ - + Renkan Auth Login diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/templates/fragment/groupForm.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/webapp/WEB-INF/templates/fragment/groupForm.html Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,84 @@ + + + + + User form + + +
+ +
+
+ +
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+
+
+ + \ No newline at end of file diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/templates/fragment/pageFragment.html --- a/server/src/main/webapp/WEB-INF/templates/fragment/pageFragment.html Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/webapp/WEB-INF/templates/fragment/pageFragment.html Wed Jan 15 18:36:27 2014 +0100 @@ -1,7 +1,8 @@ + xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3" + th:lang="${#ctx.getLocale().toLanguageTag()}" > pagination fragment @@ -13,8 +14,8 @@
username | - home | - admin | + home | + admin | logout
diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/templates/fragment/paginationFragment.html --- a/server/src/main/webapp/WEB-INF/templates/fragment/paginationFragment.html Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/webapp/WEB-INF/templates/fragment/paginationFragment.html Wed Jan 15 18:36:27 2014 +0100 @@ -1,6 +1,5 @@ - + pagination fragment @@ -18,8 +17,8 @@ > >> -
- << +
+ << < ... 3 diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/templates/fragment/spaceForm.html --- a/server/src/main/webapp/WEB-INF/templates/fragment/spaceForm.html Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/webapp/WEB-INF/templates/fragment/spaceForm.html Wed Jan 15 18:36:27 2014 +0100 @@ -1,5 +1,5 @@ - + Space form @@ -8,63 +8,46 @@
-
+
diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/templates/fragment/userForm.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/webapp/WEB-INF/templates/fragment/userForm.html Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,155 @@ + + + + + User form + + +
+ + +
+ +
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+
+ + + + +
+
+ + + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+
+ + +
+ +
+ +
+ + \ No newline at end of file diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/templates/projectIndex.html --- a/server/src/main/webapp/WEB-INF/templates/projectIndex.html Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/webapp/WEB-INF/templates/projectIndex.html Wed Jan 15 18:36:27 2014 +0100 @@ -1,5 +1,5 @@ - + Renkan diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/templates/renkanIndex.html --- a/server/src/main/webapp/WEB-INF/templates/renkanIndex.html Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/webapp/WEB-INF/templates/renkanIndex.html Wed Jan 15 18:36:27 2014 +0100 @@ -1,5 +1,5 @@ - + Renkan @@ -54,7 +54,7 @@ Name Creation Project count - Edit + Open diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/templates/renkanProjectEdit.html --- a/server/src/main/webapp/WEB-INF/templates/renkanProjectEdit.html Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/webapp/WEB-INF/templates/renkanProjectEdit.html Wed Jan 15 18:36:27 2014 +0100 @@ -1,5 +1,5 @@ - + diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/templates/renkanProjectPublish.html --- a/server/src/main/webapp/WEB-INF/templates/renkanProjectPublish.html Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/webapp/WEB-INF/templates/renkanProjectPublish.html Wed Jan 15 18:36:27 2014 +0100 @@ -1,5 +1,5 @@ - + diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/WEB-INF/web.xml --- a/server/src/main/webapp/WEB-INF/web.xml Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/webapp/WEB-INF/web.xml Wed Jan 15 18:36:27 2014 +0100 @@ -2,15 +2,15 @@ + xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" + version="3.0"> org.springframework.web.context.ContextLoaderListener org.springframework.web.context.request.RequestContextListener - + contextConfigLocation /WEB-INF/applicationContext.xml @@ -66,20 +66,16 @@ /ocw_admin/* - rest Servlet - com.sun.jersey.spi.spring.container.servlet.SpringServlet + restServlet + org.glassfish.jersey.servlet.ServletContainer - com.sun.jersey.config.property.packages - org.iri_research.renkan.rest - - - com.sun.jersey.api.json.POJOMappingFeature - true + javax.ws.rs.Application + org.iri_research.renkan.rest.RestApplication 1 - rest Servlet + restServlet /rest/* diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/static/css/index.css --- a/server/src/main/webapp/static/css/index.css Fri Oct 25 16:42:11 2013 +0200 +++ b/server/src/main/webapp/static/css/index.css Wed Jan 15 18:36:27 2014 +0100 @@ -239,24 +239,24 @@ text-decoration: none; } -.spaces-table-title { +.object-table-title { width: 250px; } -.spaces-table-created { +.object-table-created { width: 120px; } -.spaces-table-actions { +.object-table-actions { width: 40px; } -.spaces-table-actions-disabled, .spaces-table-actions-disabled:link, .spaces-table-actions-disabled:visited, .spaces-table-actions-disabled:hover, .spaces-table-actions-disabled:active, .spaces-table-actions-disabled:focus { +.object-table-actions-disabled, .object-table-actions-disabled:link, .object-table-actions-disabled:visited, .object-table-actions-disabled:hover, .object-table-actions-disabled:active, .object-table-actions-disabled:focus { color: gray; text-decoration: none; cursor: default; } -td.spaces-table-created { +td.object-table-created { text-align: center; } @@ -269,7 +269,7 @@ float: left; } -.form-fields input, .form-fields textarea { +.form-fields input, .form-fields textarea, .form-fields select { width:200px; } @@ -299,23 +299,23 @@ margin-bottom: 0; } -#space-delete-container { +#object-delete-container { margin-left: 12px; margin-top: 1em; } -#space-delete-confirm-buttons { +#object-delete-confirm-buttons { margin-top: 1em; } -#space-delete-confirm-buttons form { +#object-delete-confirm-buttons form { margin: 0; padding: 0; display: inline; } -#space-delete-confirm-buttons input[type=submit] { +#object-delete-confirm-buttons input[type=submit] { margin-right: 12px; } diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/static/js/admin_form.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/main/webapp/static/js/admin_form.js Wed Jan 15 18:36:27 2014 +0100 @@ -0,0 +1,18 @@ +function showformErrors(errors) { + $(".form-error").remove(); + + $.each(errors,function(k,v){ + $("#"+k).after('
'+v+'
'); + }); + $(".form-error").effect("highlight", {}, 1500); +} + + +function formatJson(jsonText, tabSize) { + var obj = JSON.parse(jsonText); + return JSON.stringify(obj, undefined, tabSize); +} +function compactJson(jsonText) { + var obj = JSON.parse(jsonText); + return JSON.stringify(obj); +} diff -r 2e738512336a -r 18a43ba77ad0 server/src/main/webapp/static/lib/jquery-ui.min.js --- a/server/src/main/webapp/static/lib/jquery-ui.min.js Fri Oct 25 16:42:11 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -/*! jQuery UI - v1.10.2 - 2013-04-01 -* http://jqueryui.com -* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.position.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.menu.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js, jquery.ui.effect.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js -* Copyright 2013 jQuery Foundation and other contributors Licensed MIT */ - -(function(e,t){function i(t,i){var a,n,r,o=t.nodeName.toLowerCase();return"area"===o?(a=t.parentNode,n=a.name,t.href&&n&&"map"===a.nodeName.toLowerCase()?(r=e("img[usemap=#"+n+"]")[0],!!r&&s(r)):!1):(/input|select|textarea|button|object/.test(o)?!t.disabled:"a"===o?t.href||i:i)&&s(t)}function s(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return"hidden"===e.css(this,"visibility")}).length}var a=0,n=/^ui-id-\d+$/;e.ui=e.ui||{},e.extend(e.ui,{version:"1.10.2",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({focus:function(t){return function(i,s){return"number"==typeof i?this.each(function(){var t=this;setTimeout(function(){e(t).focus(),s&&s.call(t)},i)}):t.apply(this,arguments)}}(e.fn.focus),scrollParent:function(){var t;return t=e.ui.ie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(e.css(this,"position"))&&/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0),/fixed/.test(this.css("position"))||!t.length?e(document):t},zIndex:function(i){if(i!==t)return this.css("zIndex",i);if(this.length)for(var s,a,n=e(this[0]);n.length&&n[0]!==document;){if(s=n.css("position"),("absolute"===s||"relative"===s||"fixed"===s)&&(a=parseInt(n.css("zIndex"),10),!isNaN(a)&&0!==a))return a;n=n.parent()}return 0},uniqueId:function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++a)})},removeUniqueId:function(){return this.each(function(){n.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(i){return!!e.data(i,t)}}):function(t,i,s){return!!e.data(t,s[3])},focusable:function(t){return i(t,!isNaN(e.attr(t,"tabindex")))},tabbable:function(t){var s=e.attr(t,"tabindex"),a=isNaN(s);return(a||s>=0)&&i(t,!a)}}),e("").outerWidth(1).jquery||e.each(["Width","Height"],function(i,s){function a(t,i,s,a){return e.each(n,function(){i-=parseFloat(e.css(t,"padding"+this))||0,s&&(i-=parseFloat(e.css(t,"border"+this+"Width"))||0),a&&(i-=parseFloat(e.css(t,"margin"+this))||0)}),i}var n="Width"===s?["Left","Right"]:["Top","Bottom"],r=s.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+s]=function(i){return i===t?o["inner"+s].call(this):this.each(function(){e(this).css(r,a(this,i)+"px")})},e.fn["outer"+s]=function(t,i){return"number"!=typeof t?o["outer"+s].call(this,t):this.each(function(){e(this).css(r,a(this,t,!0,i)+"px")})}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e("").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(i){return arguments.length?t.call(this,e.camelCase(i)):t.call(this)}}(e.fn.removeData)),e.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),e.support.selectstart="onselectstart"in document.createElement("div"),e.fn.extend({disableSelection:function(){return this.bind((e.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),e.extend(e.ui,{plugin:{add:function(t,i,s){var a,n=e.ui[t].prototype;for(a in s)n.plugins[a]=n.plugins[a]||[],n.plugins[a].push([i,s[a]])},call:function(e,t,i){var s,a=e.plugins[t];if(a&&e.element[0].parentNode&&11!==e.element[0].parentNode.nodeType)for(s=0;a.length>s;s++)e.options[a[s][0]]&&a[s][1].apply(e.element,i)}},hasScroll:function(t,i){if("hidden"===e(t).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",a=!1;return t[s]>0?!0:(t[s]=1,a=t[s]>0,t[s]=0,a)}})})(jQuery);(function(e,t){var i=0,s=Array.prototype.slice,n=e.cleanData;e.cleanData=function(t){for(var i,s=0;null!=(i=t[s]);s++)try{e(i).triggerHandler("remove")}catch(a){}n(t)},e.widget=function(i,s,n){var a,r,o,h,l={},u=i.split(".")[0];i=i.split(".")[1],a=u+"-"+i,n||(n=s,s=e.Widget),e.expr[":"][a.toLowerCase()]=function(t){return!!e.data(t,a)},e[u]=e[u]||{},r=e[u][i],o=e[u][i]=function(e,i){return this._createWidget?(arguments.length&&this._createWidget(e,i),t):new o(e,i)},e.extend(o,r,{version:n.version,_proto:e.extend({},n),_childConstructors:[]}),h=new s,h.options=e.widget.extend({},h.options),e.each(n,function(i,n){return e.isFunction(n)?(l[i]=function(){var e=function(){return s.prototype[i].apply(this,arguments)},t=function(e){return s.prototype[i].apply(this,e)};return function(){var i,s=this._super,a=this._superApply;return this._super=e,this._superApply=t,i=n.apply(this,arguments),this._super=s,this._superApply=a,i}}(),t):(l[i]=n,t)}),o.prototype=e.widget.extend(h,{widgetEventPrefix:r?h.widgetEventPrefix:i},l,{constructor:o,namespace:u,widgetName:i,widgetFullName:a}),r?(e.each(r._childConstructors,function(t,i){var s=i.prototype;e.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete r._childConstructors):s._childConstructors.push(o),e.widget.bridge(i,o)},e.widget.extend=function(i){for(var n,a,r=s.call(arguments,1),o=0,h=r.length;h>o;o++)for(n in r[o])a=r[o][n],r[o].hasOwnProperty(n)&&a!==t&&(i[n]=e.isPlainObject(a)?e.isPlainObject(i[n])?e.widget.extend({},i[n],a):e.widget.extend({},a):a);return i},e.widget.bridge=function(i,n){var a=n.prototype.widgetFullName||i;e.fn[i]=function(r){var o="string"==typeof r,h=s.call(arguments,1),l=this;return r=!o&&h.length?e.widget.extend.apply(null,[r].concat(h)):r,o?this.each(function(){var s,n=e.data(this,a);return n?e.isFunction(n[r])&&"_"!==r.charAt(0)?(s=n[r].apply(n,h),s!==n&&s!==t?(l=s&&s.jquery?l.pushStack(s.get()):s,!1):t):e.error("no such method '"+r+"' for "+i+" widget instance"):e.error("cannot call methods on "+i+" prior to initialization; "+"attempted to call method '"+r+"'")}):this.each(function(){var t=e.data(this,a);t?t.option(r||{})._init():e.data(this,a,new n(r,this))}),l}},e.Widget=function(){},e.Widget._childConstructors=[],e.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
",options:{disabled:!1,create:null},_createWidget:function(t,s){s=e(s||this.defaultElement||this)[0],this.element=e(s),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this.bindings=e(),this.hoverable=e(),this.focusable=e(),s!==this&&(e.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===s&&this.destroy()}}),this.document=e(s.style?s.ownerDocument:s.document||s),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(i,s){var n,a,r,o=i;if(0===arguments.length)return e.widget.extend({},this.options);if("string"==typeof i)if(o={},n=i.split("."),i=n.shift(),n.length){for(a=o[i]=e.widget.extend({},this.options[i]),r=0;n.length-1>r;r++)a[n[r]]=a[n[r]]||{},a=a[n[r]];if(i=n.pop(),s===t)return a[i]===t?null:a[i];a[i]=s}else{if(s===t)return this.options[i]===t?null:this.options[i];o[i]=s}return this._setOptions(o),this},_setOptions:function(e){var t;for(t in e)this._setOption(t,e[t]);return this},_setOption:function(e,t){return this.options[e]=t,"disabled"===e&&(this.widget().toggleClass(this.widgetFullName+"-disabled ui-state-disabled",!!t).attr("aria-disabled",t),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_on:function(i,s,n){var a,r=this;"boolean"!=typeof i&&(n=s,s=i,i=!1),n?(s=a=e(s),this.bindings=this.bindings.add(s)):(n=s,s=this.element,a=this.widget()),e.each(n,function(n,o){function h(){return i||r.options.disabled!==!0&&!e(this).hasClass("ui-state-disabled")?("string"==typeof o?r[o]:o).apply(r,arguments):t}"string"!=typeof o&&(h.guid=o.guid=o.guid||h.guid||e.guid++);var l=n.match(/^(\w+)\s*(.*)$/),u=l[1]+r.eventNamespace,c=l[2];c?a.delegate(c,u,h):s.bind(u,h)})},_off:function(e,t){t=(t||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.unbind(t).undelegate(t)},_delay:function(e,t){function i(){return("string"==typeof e?s[e]:e).apply(s,arguments)}var s=this;return setTimeout(i,t||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){e(t.currentTarget).addClass("ui-state-hover")},mouseleave:function(t){e(t.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){e(t.currentTarget).addClass("ui-state-focus")},focusout:function(t){e(t.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(t,i,s){var n,a,r=this.options[t];if(s=s||{},i=e.Event(i),i.type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),i.target=this.element[0],a=i.originalEvent)for(n in a)n in i||(i[n]=a[n]);return this.element.trigger(i,s),!(e.isFunction(r)&&r.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},e.each({show:"fadeIn",hide:"fadeOut"},function(t,i){e.Widget.prototype["_"+t]=function(s,n,a){"string"==typeof n&&(n={effect:n});var r,o=n?n===!0||"number"==typeof n?i:n.effect||i:t;n=n||{},"number"==typeof n&&(n={duration:n}),r=!e.isEmptyObject(n),n.complete=a,n.delay&&s.delay(n.delay),r&&e.effects&&e.effects.effect[o]?s[t](n):o!==t&&s[o]?s[o](n.duration,n.easing,a):s.queue(function(i){e(this)[t](),a&&a.call(s[0]),i()})}})})(jQuery);(function(e){var t=!1;e(document).mouseup(function(){t=!1}),e.widget("ui.mouse",{version:"1.10.2",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var t=this;this.element.bind("mousedown."+this.widgetName,function(e){return t._mouseDown(e)}).bind("click."+this.widgetName,function(i){return!0===e.data(i.target,t.widgetName+".preventClickEvent")?(e.removeData(i.target,t.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):undefined}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&e(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(i){if(!t){this._mouseStarted&&this._mouseUp(i),this._mouseDownEvent=i;var s=this,n=1===i.which,a="string"==typeof this.options.cancel&&i.target.nodeName?e(i.target).closest(this.options.cancel).length:!1;return n&&!a&&this._mouseCapture(i)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){s.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(i)&&this._mouseDelayMet(i)&&(this._mouseStarted=this._mouseStart(i)!==!1,!this._mouseStarted)?(i.preventDefault(),!0):(!0===e.data(i.target,this.widgetName+".preventClickEvent")&&e.removeData(i.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(e){return s._mouseMove(e)},this._mouseUpDelegate=function(e){return s._mouseUp(e)},e(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),i.preventDefault(),t=!0,!0)):!0}},_mouseMove:function(t){return e.ui.ie&&(!document.documentMode||9>document.documentMode)&&!t.button?this._mouseUp(t):this._mouseStarted?(this._mouseDrag(t),t.preventDefault()):(this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,t)!==!1,this._mouseStarted?this._mouseDrag(t):this._mouseUp(t)),!this._mouseStarted)},_mouseUp:function(t){return e(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,t.target===this._mouseDownEvent.target&&e.data(t.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(t)),!1},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}})})(jQuery);(function(t,e){function i(t,e,i){return[parseFloat(t[0])*(p.test(t[0])?e/100:1),parseFloat(t[1])*(p.test(t[1])?i/100:1)]}function s(e,i){return parseInt(t.css(e,i),10)||0}function n(e){var i=e[0];return 9===i.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(i)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()}}t.ui=t.ui||{};var a,o=Math.max,r=Math.abs,h=Math.round,l=/left|center|right/,c=/top|center|bottom/,u=/[\+\-]\d+(\.[\d]+)?%?/,d=/^\w+/,p=/%$/,f=t.fn.position;t.position={scrollbarWidth:function(){if(a!==e)return a;var i,s,n=t("
"),o=n.children()[0];return t("body").append(n),i=o.offsetWidth,n.css("overflow","scroll"),s=o.offsetWidth,i===s&&(s=n[0].clientWidth),n.remove(),a=i-s},getScrollInfo:function(e){var i=e.isWindow?"":e.element.css("overflow-x"),s=e.isWindow?"":e.element.css("overflow-y"),n="scroll"===i||"auto"===i&&e.widths?"left":i>0?"right":"center",vertical:0>a?"top":n>0?"bottom":"middle"};u>p&&p>r(i+s)&&(h.horizontal="center"),d>m&&m>r(n+a)&&(h.vertical="middle"),h.important=o(r(i),r(s))>o(r(n),r(a))?"horizontal":"vertical",e.using.call(this,t,h)}),c.offset(t.extend(C,{using:l}))})},t.ui.position={fit:{left:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=t.left-e.collisionPosition.marginLeft,h=n-r,l=r+e.collisionWidth-a-n;e.collisionWidth>a?h>0&&0>=l?(i=t.left+h+e.collisionWidth-a-n,t.left+=h-i):t.left=l>0&&0>=h?n:h>l?n+a-e.collisionWidth:n:h>0?t.left+=h:l>0?t.left-=l:t.left=o(t.left-r,t.left)},top:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollTop:s.offset.top,a=e.within.height,r=t.top-e.collisionPosition.marginTop,h=n-r,l=r+e.collisionHeight-a-n;e.collisionHeight>a?h>0&&0>=l?(i=t.top+h+e.collisionHeight-a-n,t.top+=h-i):t.top=l>0&&0>=h?n:h>l?n+a-e.collisionHeight:n:h>0?t.top+=h:l>0?t.top-=l:t.top=o(t.top-r,t.top)}},flip:{left:function(t,e){var i,s,n=e.within,a=n.offset.left+n.scrollLeft,o=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=t.left-e.collisionPosition.marginLeft,c=l-h,u=l+e.collisionWidth-o-h,d="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,p="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,f=-2*e.offset[0];0>c?(i=t.left+d+p+f+e.collisionWidth-o-a,(0>i||r(c)>i)&&(t.left+=d+p+f)):u>0&&(s=t.left-e.collisionPosition.marginLeft+d+p+f-h,(s>0||u>r(s))&&(t.left+=d+p+f))},top:function(t,e){var i,s,n=e.within,a=n.offset.top+n.scrollTop,o=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=t.top-e.collisionPosition.marginTop,c=l-h,u=l+e.collisionHeight-o-h,d="top"===e.my[1],p=d?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,f="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,m=-2*e.offset[1];0>c?(s=t.top+p+f+m+e.collisionHeight-o-a,t.top+p+f+m>c&&(0>s||r(c)>s)&&(t.top+=p+f+m)):u>0&&(i=t.top-e.collisionPosition.marginTop+p+f+m-h,t.top+p+f+m>u&&(i>0||u>r(i))&&(t.top+=p+f+m))}},flipfit:{left:function(){t.ui.position.flip.left.apply(this,arguments),t.ui.position.fit.left.apply(this,arguments)},top:function(){t.ui.position.flip.top.apply(this,arguments),t.ui.position.fit.top.apply(this,arguments)}}},function(){var e,i,s,n,a,o=document.getElementsByTagName("body")[0],r=document.createElement("div");e=document.createElement(o?"div":"body"),s={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},o&&t.extend(s,{position:"absolute",left:"-1000px",top:"-1000px"});for(a in s)e.style[a]=s[a];e.appendChild(r),i=o||document.documentElement,i.insertBefore(e,i.firstChild),r.style.cssText="position: absolute; left: 10.7432222px;",n=t(r).offset().left,t.support.offsetFractions=n>10&&11>n,e.innerHTML="",i.removeChild(e)}()})(jQuery);(function(e){e.widget("ui.draggable",e.ui.mouse,{version:"1.10.2",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"!==this.options.helper||/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},_destroy:function(){this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy()},_mouseCapture:function(t){var i=this.options;return this.helper||i.disabled||e(t.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(t),this.handle?(e(i.iframeFix===!0?"iframe":i.iframeFix).each(function(){e("
").css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(e(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(t){var i=this.options;return this.helper=this._createHelper(t),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),e.ui.ddmanager&&(e.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},e.extend(this.offset,{click:{left:t.pageX-this.offset.left,top:t.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),i.containment&&this._setContainment(),this._trigger("start",t)===!1?(this._clear(),!1):(this._cacheHelperProportions(),e.ui.ddmanager&&!i.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this._mouseDrag(t,!0),e.ui.ddmanager&&e.ui.ddmanager.dragStart(this,t),!0)},_mouseDrag:function(t,i){if(this.position=this._generatePosition(t),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",t,s)===!1)return this._mouseUp({}),!1;this.position=s.position}return this.options.axis&&"y"===this.options.axis||(this.helper[0].style.left=this.position.left+"px"),this.options.axis&&"x"===this.options.axis||(this.helper[0].style.top=this.position.top+"px"),e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),!1},_mouseStop:function(t){var i,s=this,n=!1,a=!1;for(e.ui.ddmanager&&!this.options.dropBehaviour&&(a=e.ui.ddmanager.drop(this,t)),this.dropped&&(a=this.dropped,this.dropped=!1),i=this.element[0];i&&(i=i.parentNode);)i===document&&(n=!0);return n||"original"!==this.options.helper?("invalid"===this.options.revert&&!a||"valid"===this.options.revert&&a||this.options.revert===!0||e.isFunction(this.options.revert)&&this.options.revert.call(this.element,a)?e(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){s._trigger("stop",t)!==!1&&s._clear()}):this._trigger("stop",t)!==!1&&this._clear(),!1):!1},_mouseUp:function(t){return e("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),e.ui.ddmanager&&e.ui.ddmanager.dragStop(this,t),e.ui.mouse.prototype._mouseUp.call(this,t)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(t){return this.options.handle?!!e(t.target).closest(this.element.find(this.options.handle)).length:!0},_createHelper:function(t){var i=this.options,s=e.isFunction(i.helper)?e(i.helper.apply(this.element[0],[t])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return s.parents("body").length||s.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s[0]===this.element[0]||/(fixed|absolute)/.test(s.css("position"))||s.css("position","absolute"),s},_adjustOffsetFromHelper:function(t){"string"==typeof t&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var t=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&e.ui.ie)&&(t={top:0,left:0}),{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var e=this.element.position();return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:e.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t,i,s,n=this.options;if("parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=["document"===n.containment?0:e(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,"document"===n.containment?0:e(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,("document"===n.containment?0:e(window).scrollLeft())+e("document"===n.containment?document:window).width()-this.helperProportions.width-this.margins.left,("document"===n.containment?0:e(window).scrollTop())+(e("document"===n.containment?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||n.containment.constructor===Array)n.containment.constructor===Array&&(this.containment=n.containment);else{if(i=e(n.containment),s=i[0],!s)return;t="hidden"!==e(s).css("overflow"),this.containment=[(parseInt(e(s).css("borderLeftWidth"),10)||0)+(parseInt(e(s).css("paddingLeft"),10)||0),(parseInt(e(s).css("borderTopWidth"),10)||0)+(parseInt(e(s).css("paddingTop"),10)||0),(t?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(e(s).css("borderRightWidth"),10)||0)-(parseInt(e(s).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(t?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(e(s).css("borderBottomWidth"),10)||0)-(parseInt(e(s).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=i}},_convertPositionTo:function(t,i){i||(i=this.position);var s="absolute"===t?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,a=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():a?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():a?0:n.scrollLeft())*s}},_generatePosition:function(t){var i,s,n,a,o=this.options,r="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(r[0].tagName),l=t.pageX,u=t.pageY;return this.originalPosition&&(this.containment&&(this.relative_container?(s=this.relative_container.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,t.pageX-this.offset.click.lefti[2]&&(l=i[2]+this.offset.click.left),t.pageY-this.offset.click.top>i[3]&&(u=i[3]+this.offset.click.top)),o.grid&&(n=o.grid[1]?this.originalPageY+Math.round((u-this.originalPageY)/o.grid[1])*o.grid[1]:this.originalPageY,u=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-o.grid[1]:n+o.grid[1]:n,a=o.grid[0]?this.originalPageX+Math.round((l-this.originalPageX)/o.grid[0])*o.grid[0]:this.originalPageX,l=i?a-this.offset.click.left>=i[0]||a-this.offset.click.left>i[2]?a:a-this.offset.click.left>=i[0]?a-o.grid[0]:a+o.grid[0]:a)),{top:u-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:r.scrollTop()),left:l-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:r.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1},_trigger:function(t,i,s){return s=s||this._uiHash(),e.ui.plugin.call(this,t,[i,s]),"drag"===t&&(this.positionAbs=this._convertPositionTo("absolute")),e.Widget.prototype._trigger.call(this,t,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),e.ui.plugin.add("draggable","connectToSortable",{start:function(t,i){var s=e(this).data("ui-draggable"),n=s.options,a=e.extend({},i,{item:s.element});s.sortables=[],e(n.connectToSortable).each(function(){var i=e.data(this,"ui-sortable");i&&!i.options.disabled&&(s.sortables.push({instance:i,shouldRevert:i.options.revert}),i.refreshPositions(),i._trigger("activate",t,a))})},stop:function(t,i){var s=e(this).data("ui-draggable"),n=e.extend({},i,{item:s.element});e.each(s.sortables,function(){this.instance.isOver?(this.instance.isOver=0,s.cancelHelperRemoval=!0,this.instance.cancelHelperRemoval=!1,this.shouldRevert&&(this.instance.options.revert=this.shouldRevert),this.instance._mouseStop(t),this.instance.options.helper=this.instance.options._helper,"original"===s.options.helper&&this.instance.currentItem.css({top:"auto",left:"auto"})):(this.instance.cancelHelperRemoval=!1,this.instance._trigger("deactivate",t,n))})},drag:function(t,i){var s=e(this).data("ui-draggable"),n=this;e.each(s.sortables,function(){var a=!1,o=this;this.instance.positionAbs=s.positionAbs,this.instance.helperProportions=s.helperProportions,this.instance.offset.click=s.offset.click,this.instance._intersectsWith(this.instance.containerCache)&&(a=!0,e.each(s.sortables,function(){return this.instance.positionAbs=s.positionAbs,this.instance.helperProportions=s.helperProportions,this.instance.offset.click=s.offset.click,this!==o&&this.instance._intersectsWith(this.instance.containerCache)&&e.contains(o.instance.element[0],this.instance.element[0])&&(a=!1),a})),a?(this.instance.isOver||(this.instance.isOver=1,this.instance.currentItem=e(n).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item",!0),this.instance.options._helper=this.instance.options.helper,this.instance.options.helper=function(){return i.helper[0]},t.target=this.instance.currentItem[0],this.instance._mouseCapture(t,!0),this.instance._mouseStart(t,!0,!0),this.instance.offset.click.top=s.offset.click.top,this.instance.offset.click.left=s.offset.click.left,this.instance.offset.parent.left-=s.offset.parent.left-this.instance.offset.parent.left,this.instance.offset.parent.top-=s.offset.parent.top-this.instance.offset.parent.top,s._trigger("toSortable",t),s.dropped=this.instance.element,s.currentItem=s.element,this.instance.fromOutside=s),this.instance.currentItem&&this.instance._mouseDrag(t)):this.instance.isOver&&(this.instance.isOver=0,this.instance.cancelHelperRemoval=!0,this.instance.options.revert=!1,this.instance._trigger("out",t,this.instance._uiHash(this.instance)),this.instance._mouseStop(t,!0),this.instance.options.helper=this.instance.options._helper,this.instance.currentItem.remove(),this.instance.placeholder&&this.instance.placeholder.remove(),s._trigger("fromSortable",t),s.dropped=!1)})}}),e.ui.plugin.add("draggable","cursor",{start:function(){var t=e("body"),i=e(this).data("ui-draggable").options;t.css("cursor")&&(i._cursor=t.css("cursor")),t.css("cursor",i.cursor)},stop:function(){var t=e(this).data("ui-draggable").options;t._cursor&&e("body").css("cursor",t._cursor)}}),e.ui.plugin.add("draggable","opacity",{start:function(t,i){var s=e(i.helper),n=e(this).data("ui-draggable").options;s.css("opacity")&&(n._opacity=s.css("opacity")),s.css("opacity",n.opacity)},stop:function(t,i){var s=e(this).data("ui-draggable").options;s._opacity&&e(i.helper).css("opacity",s._opacity)}}),e.ui.plugin.add("draggable","scroll",{start:function(){var t=e(this).data("ui-draggable");t.scrollParent[0]!==document&&"HTML"!==t.scrollParent[0].tagName&&(t.overflowOffset=t.scrollParent.offset())},drag:function(t){var i=e(this).data("ui-draggable"),s=i.options,n=!1;i.scrollParent[0]!==document&&"HTML"!==i.scrollParent[0].tagName?(s.axis&&"x"===s.axis||(i.overflowOffset.top+i.scrollParent[0].offsetHeight-t.pageY=0;c--)r=p.snapElements[c].left,h=r+p.snapElements[c].width,l=p.snapElements[c].top,u=l+p.snapElements[c].height,g>r-m&&h+m>g&&y>l-m&&u+m>y||g>r-m&&h+m>g&&b>l-m&&u+m>b||v>r-m&&h+m>v&&y>l-m&&u+m>y||v>r-m&&h+m>v&&b>l-m&&u+m>b?("inner"!==f.snapMode&&(s=m>=Math.abs(l-b),n=m>=Math.abs(u-y),a=m>=Math.abs(r-v),o=m>=Math.abs(h-g),s&&(i.position.top=p._convertPositionTo("relative",{top:l-p.helperProportions.height,left:0}).top-p.margins.top),n&&(i.position.top=p._convertPositionTo("relative",{top:u,left:0}).top-p.margins.top),a&&(i.position.left=p._convertPositionTo("relative",{top:0,left:r-p.helperProportions.width}).left-p.margins.left),o&&(i.position.left=p._convertPositionTo("relative",{top:0,left:h}).left-p.margins.left)),d=s||n||a||o,"outer"!==f.snapMode&&(s=m>=Math.abs(l-y),n=m>=Math.abs(u-b),a=m>=Math.abs(r-g),o=m>=Math.abs(h-v),s&&(i.position.top=p._convertPositionTo("relative",{top:l,left:0}).top-p.margins.top),n&&(i.position.top=p._convertPositionTo("relative",{top:u-p.helperProportions.height,left:0}).top-p.margins.top),a&&(i.position.left=p._convertPositionTo("relative",{top:0,left:r}).left-p.margins.left),o&&(i.position.left=p._convertPositionTo("relative",{top:0,left:h-p.helperProportions.width}).left-p.margins.left)),!p.snapElements[c].snapping&&(s||n||a||o||d)&&p.options.snap.snap&&p.options.snap.snap.call(p.element,t,e.extend(p._uiHash(),{snapItem:p.snapElements[c].item})),p.snapElements[c].snapping=s||n||a||o||d):(p.snapElements[c].snapping&&p.options.snap.release&&p.options.snap.release.call(p.element,t,e.extend(p._uiHash(),{snapItem:p.snapElements[c].item})),p.snapElements[c].snapping=!1)}}),e.ui.plugin.add("draggable","stack",{start:function(){var t,i=this.data("ui-draggable").options,s=e.makeArray(e(i.stack)).sort(function(t,i){return(parseInt(e(t).css("zIndex"),10)||0)-(parseInt(e(i).css("zIndex"),10)||0)});s.length&&(t=parseInt(e(s[0]).css("zIndex"),10)||0,e(s).each(function(i){e(this).css("zIndex",t+i)}),this.css("zIndex",t+s.length))}}),e.ui.plugin.add("draggable","zIndex",{start:function(t,i){var s=e(i.helper),n=e(this).data("ui-draggable").options;s.css("zIndex")&&(n._zIndex=s.css("zIndex")),s.css("zIndex",n.zIndex)},stop:function(t,i){var s=e(this).data("ui-draggable").options;s._zIndex&&e(i.helper).css("zIndex",s._zIndex)}})})(jQuery);(function(e){function t(e,t,i){return e>t&&t+i>e}e.widget("ui.droppable",{version:"1.10.2",widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect",activate:null,deactivate:null,drop:null,out:null,over:null},_create:function(){var t=this.options,i=t.accept;this.isover=!1,this.isout=!0,this.accept=e.isFunction(i)?i:function(e){return e.is(i)},this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight},e.ui.ddmanager.droppables[t.scope]=e.ui.ddmanager.droppables[t.scope]||[],e.ui.ddmanager.droppables[t.scope].push(this),t.addClasses&&this.element.addClass("ui-droppable")},_destroy:function(){for(var t=0,i=e.ui.ddmanager.droppables[this.options.scope];i.length>t;t++)i[t]===this&&i.splice(t,1);this.element.removeClass("ui-droppable ui-droppable-disabled")},_setOption:function(t,i){"accept"===t&&(this.accept=e.isFunction(i)?i:function(e){return e.is(i)}),e.Widget.prototype._setOption.apply(this,arguments)},_activate:function(t){var i=e.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),i&&this._trigger("activate",t,this.ui(i))},_deactivate:function(t){var i=e.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),i&&this._trigger("deactivate",t,this.ui(i))},_over:function(t){var i=e.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",t,this.ui(i)))},_out:function(t){var i=e.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",t,this.ui(i)))},_drop:function(t,i){var s=i||e.ui.ddmanager.current,n=!1;return s&&(s.currentItem||s.element)[0]!==this.element[0]?(this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function(){var t=e.data(this,"ui-droppable");return t.options.greedy&&!t.options.disabled&&t.options.scope===s.options.scope&&t.accept.call(t.element[0],s.currentItem||s.element)&&e.ui.intersect(s,e.extend(t,{offset:t.element.offset()}),t.options.tolerance)?(n=!0,!1):undefined}),n?!1:this.accept.call(this.element[0],s.currentItem||s.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",t,this.ui(s)),this.element):!1):!1},ui:function(e){return{draggable:e.currentItem||e.element,helper:e.helper,position:e.position,offset:e.positionAbs}}}),e.ui.intersect=function(e,i,s){if(!i.offset)return!1;var n,a,o=(e.positionAbs||e.position.absolute).left,r=o+e.helperProportions.width,h=(e.positionAbs||e.position.absolute).top,l=h+e.helperProportions.height,u=i.offset.left,c=u+i.proportions.width,d=i.offset.top,p=d+i.proportions.height;switch(s){case"fit":return o>=u&&c>=r&&h>=d&&p>=l;case"intersect":return o+e.helperProportions.width/2>u&&c>r-e.helperProportions.width/2&&h+e.helperProportions.height/2>d&&p>l-e.helperProportions.height/2;case"pointer":return n=(e.positionAbs||e.position.absolute).left+(e.clickOffset||e.offset.click).left,a=(e.positionAbs||e.position.absolute).top+(e.clickOffset||e.offset.click).top,t(a,d,i.proportions.height)&&t(n,u,i.proportions.width);case"touch":return(h>=d&&p>=h||l>=d&&p>=l||d>h&&l>p)&&(o>=u&&c>=o||r>=u&&c>=r||u>o&&r>c);default:return!1}},e.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(t,i){var s,n,a=e.ui.ddmanager.droppables[t.options.scope]||[],o=i?i.type:null,r=(t.currentItem||t.element).find(":data(ui-droppable)").addBack();e:for(s=0;a.length>s;s++)if(!(a[s].options.disabled||t&&!a[s].accept.call(a[s].element[0],t.currentItem||t.element))){for(n=0;r.length>n;n++)if(r[n]===a[s].element[0]){a[s].proportions.height=0;continue e}a[s].visible="none"!==a[s].element.css("display"),a[s].visible&&("mousedown"===o&&a[s]._activate.call(a[s],i),a[s].offset=a[s].element.offset(),a[s].proportions={width:a[s].element[0].offsetWidth,height:a[s].element[0].offsetHeight})}},drop:function(t,i){var s=!1;return e.each((e.ui.ddmanager.droppables[t.options.scope]||[]).slice(),function(){this.options&&(!this.options.disabled&&this.visible&&e.ui.intersect(t,this,this.options.tolerance)&&(s=this._drop.call(this,i)||s),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],t.currentItem||t.element)&&(this.isout=!0,this.isover=!1,this._deactivate.call(this,i)))}),s},dragStart:function(t,i){t.element.parentsUntil("body").bind("scroll.droppable",function(){t.options.refreshPositions||e.ui.ddmanager.prepareOffsets(t,i)})},drag:function(t,i){t.options.refreshPositions&&e.ui.ddmanager.prepareOffsets(t,i),e.each(e.ui.ddmanager.droppables[t.options.scope]||[],function(){if(!this.options.disabled&&!this.greedyChild&&this.visible){var s,n,a,o=e.ui.intersect(t,this,this.options.tolerance),r=!o&&this.isover?"isout":o&&!this.isover?"isover":null;r&&(this.options.greedy&&(n=this.options.scope,a=this.element.parents(":data(ui-droppable)").filter(function(){return e.data(this,"ui-droppable").options.scope===n}),a.length&&(s=e.data(a[0],"ui-droppable"),s.greedyChild="isover"===r)),s&&"isover"===r&&(s.isover=!1,s.isout=!0,s._out.call(s,i)),this[r]=!0,this["isout"===r?"isover":"isout"]=!1,this["isover"===r?"_over":"_out"].call(this,i),s&&"isout"===r&&(s.isout=!1,s.isover=!0,s._over.call(s,i)))}})},dragStop:function(t,i){t.element.parentsUntil("body").unbind("scroll.droppable"),t.options.refreshPositions||e.ui.ddmanager.prepareOffsets(t,i)}}})(jQuery);(function(e){function t(e){return parseInt(e,10)||0}function i(e){return!isNaN(parseInt(e,10))}e.widget("ui.resizable",e.ui.mouse,{version:"1.10.2",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_create:function(){var t,i,s,n,a,o=this,r=this.options;if(this.element.addClass("ui-resizable"),e.extend(this,{_aspectRatio:!!r.aspectRatio,aspectRatio:r.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:r.helper||r.ghost||r.animate?r.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(e("
").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.data("ui-resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=r.handles||(e(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),t=this.handles.split(","),this.handles={},i=0;t.length>i;i++)s=e.trim(t[i]),a="ui-resizable-"+s,n=e("
"),n.css({zIndex:r.zIndex}),"se"===s&&n.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[s]=".ui-resizable-"+s,this.element.append(n);this._renderAxis=function(t){var i,s,n,a;t=t||this.element;for(i in this.handles)this.handles[i].constructor===String&&(this.handles[i]=e(this.handles[i],this.element).show()),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)&&(s=e(this.handles[i],this.element),a=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),t.css(n,a),this._proportionallyResize()),e(this.handles[i]).length},this._renderAxis(this.element),this._handles=e(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){o.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),o.axis=n&&n[1]?n[1]:"se")}),r.autoHide&&(this._handles.hide(),e(this.element).addClass("ui-resizable-autohide").mouseenter(function(){r.disabled||(e(this).removeClass("ui-resizable-autohide"),o._handles.show())}).mouseleave(function(){r.disabled||o.resizing||(e(this).addClass("ui-resizable-autohide"),o._handles.hide())})),this._mouseInit()},_destroy:function(){this._mouseDestroy();var t,i=function(t){e(t).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),t=this.element,this.originalElement.css({position:t.css("position"),width:t.outerWidth(),height:t.outerHeight(),top:t.css("top"),left:t.css("left")}).insertAfter(t),t.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_mouseCapture:function(t){var i,s,n=!1;for(i in this.handles)s=e(this.handles[i])[0],(s===t.target||e.contains(s,t.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(i){var s,n,a,o=this.options,r=this.element.position(),h=this.element;return this.resizing=!0,/absolute/.test(h.css("position"))?h.css({position:"absolute",top:h.css("top"),left:h.css("left")}):h.is(".ui-draggable")&&h.css({position:"absolute",top:r.top,left:r.left}),this._renderProxy(),s=t(this.helper.css("left")),n=t(this.helper.css("top")),o.containment&&(s+=e(o.containment).scrollLeft()||0,n+=e(o.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:s,top:n},this.size=this._helper?{width:h.outerWidth(),height:h.outerHeight()}:{width:h.width(),height:h.height()},this.originalSize=this._helper?{width:h.outerWidth(),height:h.outerHeight()}:{width:h.width(),height:h.height()},this.originalPosition={left:s,top:n},this.sizeDiff={width:h.outerWidth()-h.width(),height:h.outerHeight()-h.height()},this.originalMousePosition={left:i.pageX,top:i.pageY},this.aspectRatio="number"==typeof o.aspectRatio?o.aspectRatio:this.originalSize.width/this.originalSize.height||1,a=e(".ui-resizable-"+this.axis).css("cursor"),e("body").css("cursor","auto"===a?this.axis+"-resize":a),h.addClass("ui-resizable-resizing"),this._propagate("start",i),!0},_mouseDrag:function(t){var i,s=this.helper,n={},a=this.originalMousePosition,o=this.axis,r=this.position.top,h=this.position.left,l=this.size.width,u=this.size.height,c=t.pageX-a.left||0,d=t.pageY-a.top||0,p=this._change[o];return p?(i=p.apply(this,[t,c,d]),this._updateVirtualBoundaries(t.shiftKey),(this._aspectRatio||t.shiftKey)&&(i=this._updateRatio(i,t)),i=this._respectSize(i,t),this._updateCache(i),this._propagate("resize",t),this.position.top!==r&&(n.top=this.position.top+"px"),this.position.left!==h&&(n.left=this.position.left+"px"),this.size.width!==l&&(n.width=this.size.width+"px"),this.size.height!==u&&(n.height=this.size.height+"px"),s.css(n),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),e.isEmptyObject(n)||this._trigger("resize",t,this.ui()),!1):!1},_mouseStop:function(t){this.resizing=!1;var i,s,n,a,o,r,h,l=this.options,u=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&e.ui.hasScroll(i[0],"left")?0:u.sizeDiff.height,a=s?0:u.sizeDiff.width,o={width:u.helper.width()-a,height:u.helper.height()-n},r=parseInt(u.element.css("left"),10)+(u.position.left-u.originalPosition.left)||null,h=parseInt(u.element.css("top"),10)+(u.position.top-u.originalPosition.top)||null,l.animate||this.element.css(e.extend(o,{top:h,left:r})),u.helper.height(u.size.height),u.helper.width(u.size.width),this._helper&&!l.animate&&this._proportionallyResize()),e("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",t),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(e){var t,s,n,a,o,r=this.options;o={minWidth:i(r.minWidth)?r.minWidth:0,maxWidth:i(r.maxWidth)?r.maxWidth:1/0,minHeight:i(r.minHeight)?r.minHeight:0,maxHeight:i(r.maxHeight)?r.maxHeight:1/0},(this._aspectRatio||e)&&(t=o.minHeight*this.aspectRatio,n=o.minWidth/this.aspectRatio,s=o.maxHeight*this.aspectRatio,a=o.maxWidth/this.aspectRatio,t>o.minWidth&&(o.minWidth=t),n>o.minHeight&&(o.minHeight=n),o.maxWidth>s&&(o.maxWidth=s),o.maxHeight>a&&(o.maxHeight=a)),this._vBoundaries=o},_updateCache:function(e){this.offset=this.helper.offset(),i(e.left)&&(this.position.left=e.left),i(e.top)&&(this.position.top=e.top),i(e.height)&&(this.size.height=e.height),i(e.width)&&(this.size.width=e.width)},_updateRatio:function(e){var t=this.position,s=this.size,n=this.axis;return i(e.height)?e.width=e.height*this.aspectRatio:i(e.width)&&(e.height=e.width/this.aspectRatio),"sw"===n&&(e.left=t.left+(s.width-e.width),e.top=null),"nw"===n&&(e.top=t.top+(s.height-e.height),e.left=t.left+(s.width-e.width)),e},_respectSize:function(e){var t=this._vBoundaries,s=this.axis,n=i(e.width)&&t.maxWidth&&t.maxWidthe.width,r=i(e.height)&&t.minHeight&&t.minHeight>e.height,h=this.originalPosition.left+this.originalSize.width,l=this.position.top+this.size.height,u=/sw|nw|w/.test(s),c=/nw|ne|n/.test(s);return o&&(e.width=t.minWidth),r&&(e.height=t.minHeight),n&&(e.width=t.maxWidth),a&&(e.height=t.maxHeight),o&&u&&(e.left=h-t.minWidth),n&&u&&(e.left=h-t.maxWidth),r&&c&&(e.top=l-t.minHeight),a&&c&&(e.top=l-t.maxHeight),e.width||e.height||e.left||!e.top?e.width||e.height||e.top||!e.left||(e.left=null):e.top=null,e},_proportionallyResize:function(){if(this._proportionallyResizeElements.length){var e,t,i,s,n,a=this.helper||this.element;for(e=0;this._proportionallyResizeElements.length>e;e++){if(n=this._proportionallyResizeElements[e],!this.borderDif)for(this.borderDif=[],i=[n.css("borderTopWidth"),n.css("borderRightWidth"),n.css("borderBottomWidth"),n.css("borderLeftWidth")],s=[n.css("paddingTop"),n.css("paddingRight"),n.css("paddingBottom"),n.css("paddingLeft")],t=0;i.length>t;t++)this.borderDif[t]=(parseInt(i[t],10)||0)+(parseInt(s[t],10)||0);n.css({height:a.height()-this.borderDif[0]-this.borderDif[2]||0,width:a.width()-this.borderDif[1]-this.borderDif[3]||0})}}},_renderProxy:function(){var t=this.element,i=this.options;this.elementOffset=t.offset(),this._helper?(this.helper=this.helper||e("
"),this.helper.addClass(this._helper).css({width:this.element.outerWidth()-1,height:this.element.outerHeight()-1,position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(e,t){return{width:this.originalSize.width+t}},w:function(e,t){var i=this.originalSize,s=this.originalPosition;return{left:s.left+t,width:i.width-t}},n:function(e,t,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(e,t,i){return{height:this.originalSize.height+i}},se:function(t,i,s){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[t,i,s]))},sw:function(t,i,s){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[t,i,s]))},ne:function(t,i,s){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[t,i,s]))},nw:function(t,i,s){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[t,i,s]))}},_propagate:function(t,i){e.ui.plugin.call(this,t,[i,this.ui()]),"resize"!==t&&this._trigger(t,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),e.ui.plugin.add("resizable","animate",{stop:function(t){var i=e(this).data("ui-resizable"),s=i.options,n=i._proportionallyResizeElements,a=n.length&&/textarea/i.test(n[0].nodeName),o=a&&e.ui.hasScroll(n[0],"left")?0:i.sizeDiff.height,r=a?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-o},l=parseInt(i.element.css("left"),10)+(i.position.left-i.originalPosition.left)||null,u=parseInt(i.element.css("top"),10)+(i.position.top-i.originalPosition.top)||null;i.element.animate(e.extend(h,u&&l?{top:u,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseInt(i.element.css("width"),10),height:parseInt(i.element.css("height"),10),top:parseInt(i.element.css("top"),10),left:parseInt(i.element.css("left"),10)};n&&n.length&&e(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",t)}})}}),e.ui.plugin.add("resizable","containment",{start:function(){var i,s,n,a,o,r,h,l=e(this).data("ui-resizable"),u=l.options,c=l.element,d=u.containment,p=d instanceof e?d.get(0):/parent/.test(d)?c.parent().get(0):d;p&&(l.containerElement=e(p),/document/.test(d)||d===document?(l.containerOffset={left:0,top:0},l.containerPosition={left:0,top:0},l.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}):(i=e(p),s=[],e(["Top","Right","Left","Bottom"]).each(function(e,n){s[e]=t(i.css("padding"+n))}),l.containerOffset=i.offset(),l.containerPosition=i.position(),l.containerSize={height:i.innerHeight()-s[3],width:i.innerWidth()-s[1]},n=l.containerOffset,a=l.containerSize.height,o=l.containerSize.width,r=e.ui.hasScroll(p,"left")?p.scrollWidth:o,h=e.ui.hasScroll(p)?p.scrollHeight:a,l.parentData={element:p,left:n.left,top:n.top,width:r,height:h}))},resize:function(t){var i,s,n,a,o=e(this).data("ui-resizable"),r=o.options,h=o.containerOffset,l=o.position,u=o._aspectRatio||t.shiftKey,c={top:0,left:0},d=o.containerElement;d[0]!==document&&/static/.test(d.css("position"))&&(c=h),l.left<(o._helper?h.left:0)&&(o.size.width=o.size.width+(o._helper?o.position.left-h.left:o.position.left-c.left),u&&(o.size.height=o.size.width/o.aspectRatio),o.position.left=r.helper?h.left:0),l.top<(o._helper?h.top:0)&&(o.size.height=o.size.height+(o._helper?o.position.top-h.top:o.position.top),u&&(o.size.width=o.size.height*o.aspectRatio),o.position.top=o._helper?h.top:0),o.offset.left=o.parentData.left+o.position.left,o.offset.top=o.parentData.top+o.position.top,i=Math.abs((o._helper?o.offset.left-c.left:o.offset.left-c.left)+o.sizeDiff.width),s=Math.abs((o._helper?o.offset.top-c.top:o.offset.top-h.top)+o.sizeDiff.height),n=o.containerElement.get(0)===o.element.parent().get(0),a=/relative|absolute/.test(o.containerElement.css("position")),n&&a&&(i-=o.parentData.left),i+o.size.width>=o.parentData.width&&(o.size.width=o.parentData.width-i,u&&(o.size.height=o.size.width/o.aspectRatio)),s+o.size.height>=o.parentData.height&&(o.size.height=o.parentData.height-s,u&&(o.size.width=o.size.height*o.aspectRatio))},stop:function(){var t=e(this).data("ui-resizable"),i=t.options,s=t.containerOffset,n=t.containerPosition,a=t.containerElement,o=e(t.helper),r=o.offset(),h=o.outerWidth()-t.sizeDiff.width,l=o.outerHeight()-t.sizeDiff.height;t._helper&&!i.animate&&/relative/.test(a.css("position"))&&e(this).css({left:r.left-n.left-s.left,width:h,height:l}),t._helper&&!i.animate&&/static/.test(a.css("position"))&&e(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),e.ui.plugin.add("resizable","alsoResize",{start:function(){var t=e(this).data("ui-resizable"),i=t.options,s=function(t){e(t).each(function(){var t=e(this);t.data("ui-resizable-alsoresize",{width:parseInt(t.width(),10),height:parseInt(t.height(),10),left:parseInt(t.css("left"),10),top:parseInt(t.css("top"),10)})})};"object"!=typeof i.alsoResize||i.alsoResize.parentNode?s(i.alsoResize):i.alsoResize.length?(i.alsoResize=i.alsoResize[0],s(i.alsoResize)):e.each(i.alsoResize,function(e){s(e)})},resize:function(t,i){var s=e(this).data("ui-resizable"),n=s.options,a=s.originalSize,o=s.originalPosition,r={height:s.size.height-a.height||0,width:s.size.width-a.width||0,top:s.position.top-o.top||0,left:s.position.left-o.left||0},h=function(t,s){e(t).each(function(){var t=e(this),n=e(this).data("ui-resizable-alsoresize"),a={},o=s&&s.length?s:t.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(o,function(e,t){var i=(n[t]||0)+(r[t]||0);i&&i>=0&&(a[t]=i||null)}),t.css(a)})};"object"!=typeof n.alsoResize||n.alsoResize.nodeType?h(n.alsoResize):e.each(n.alsoResize,function(e,t){h(e,t)})},stop:function(){e(this).removeData("resizable-alsoresize")}}),e.ui.plugin.add("resizable","ghost",{start:function(){var t=e(this).data("ui-resizable"),i=t.options,s=t.size;t.ghost=t.originalElement.clone(),t.ghost.css({opacity:.25,display:"block",position:"relative",height:s.height,width:s.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass("string"==typeof i.ghost?i.ghost:""),t.ghost.appendTo(t.helper)},resize:function(){var t=e(this).data("ui-resizable");t.ghost&&t.ghost.css({position:"relative",height:t.size.height,width:t.size.width})},stop:function(){var t=e(this).data("ui-resizable");t.ghost&&t.helper&&t.helper.get(0).removeChild(t.ghost.get(0))}}),e.ui.plugin.add("resizable","grid",{resize:function(){var t=e(this).data("ui-resizable"),i=t.options,s=t.size,n=t.originalSize,a=t.originalPosition,o=t.axis,r="number"==typeof i.grid?[i.grid,i.grid]:i.grid,h=r[0]||1,l=r[1]||1,u=Math.round((s.width-n.width)/h)*h,c=Math.round((s.height-n.height)/l)*l,d=n.width+u,p=n.height+c,f=i.maxWidth&&d>i.maxWidth,m=i.maxHeight&&p>i.maxHeight,g=i.minWidth&&i.minWidth>d,v=i.minHeight&&i.minHeight>p;i.grid=r,g&&(d+=h),v&&(p+=l),f&&(d-=h),m&&(p-=l),/^(se|s|e)$/.test(o)?(t.size.width=d,t.size.height=p):/^(ne)$/.test(o)?(t.size.width=d,t.size.height=p,t.position.top=a.top-c):/^(sw)$/.test(o)?(t.size.width=d,t.size.height=p,t.position.left=a.left-u):(t.size.width=d,t.size.height=p,t.position.top=a.top-c,t.position.left=a.left-u)}})})(jQuery);(function(e){e.widget("ui.selectable",e.ui.mouse,{version:"1.10.2",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch",selected:null,selecting:null,start:null,stop:null,unselected:null,unselecting:null},_create:function(){var t,i=this;this.element.addClass("ui-selectable"),this.dragged=!1,this.refresh=function(){t=e(i.options.filter,i.element[0]),t.addClass("ui-selectee"),t.each(function(){var t=e(this),i=t.offset();e.data(this,"selectable-item",{element:this,$element:t,left:i.left,top:i.top,right:i.left+t.outerWidth(),bottom:i.top+t.outerHeight(),startselected:!1,selected:t.hasClass("ui-selected"),selecting:t.hasClass("ui-selecting"),unselecting:t.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=t.addClass("ui-selectee"),this._mouseInit(),this.helper=e("
")},_destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled"),this._mouseDestroy()},_mouseStart:function(t){var i=this,s=this.options;this.opos=[t.pageX,t.pageY],this.options.disabled||(this.selectees=e(s.filter,this.element[0]),this._trigger("start",t),e(s.appendTo).append(this.helper),this.helper.css({left:t.pageX,top:t.pageY,width:0,height:0}),s.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var s=e.data(this,"selectable-item");s.startselected=!0,t.metaKey||t.ctrlKey||(s.$element.removeClass("ui-selected"),s.selected=!1,s.$element.addClass("ui-unselecting"),s.unselecting=!0,i._trigger("unselecting",t,{unselecting:s.element}))}),e(t.target).parents().addBack().each(function(){var s,n=e.data(this,"selectable-item");return n?(s=!t.metaKey&&!t.ctrlKey||!n.$element.hasClass("ui-selected"),n.$element.removeClass(s?"ui-unselecting":"ui-selected").addClass(s?"ui-selecting":"ui-unselecting"),n.unselecting=!s,n.selecting=s,n.selected=s,s?i._trigger("selecting",t,{selecting:n.element}):i._trigger("unselecting",t,{unselecting:n.element}),!1):undefined}))},_mouseDrag:function(t){if(this.dragged=!0,!this.options.disabled){var i,s=this,n=this.options,a=this.opos[0],o=this.opos[1],r=t.pageX,h=t.pageY;return a>r&&(i=r,r=a,a=i),o>h&&(i=h,h=o,o=i),this.helper.css({left:a,top:o,width:r-a,height:h-o}),this.selectees.each(function(){var i=e.data(this,"selectable-item"),l=!1;i&&i.element!==s.element[0]&&("touch"===n.tolerance?l=!(i.left>r||a>i.right||i.top>h||o>i.bottom):"fit"===n.tolerance&&(l=i.left>a&&r>i.right&&i.top>o&&h>i.bottom),l?(i.selected&&(i.$element.removeClass("ui-selected"),i.selected=!1),i.unselecting&&(i.$element.removeClass("ui-unselecting"),i.unselecting=!1),i.selecting||(i.$element.addClass("ui-selecting"),i.selecting=!0,s._trigger("selecting",t,{selecting:i.element}))):(i.selecting&&((t.metaKey||t.ctrlKey)&&i.startselected?(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.$element.addClass("ui-selected"),i.selected=!0):(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.startselected&&(i.$element.addClass("ui-unselecting"),i.unselecting=!0),s._trigger("unselecting",t,{unselecting:i.element}))),i.selected&&(t.metaKey||t.ctrlKey||i.startselected||(i.$element.removeClass("ui-selected"),i.selected=!1,i.$element.addClass("ui-unselecting"),i.unselecting=!0,s._trigger("unselecting",t,{unselecting:i.element})))))}),!1}},_mouseStop:function(t){var i=this;return this.dragged=!1,e(".ui-unselecting",this.element[0]).each(function(){var s=e.data(this,"selectable-item");s.$element.removeClass("ui-unselecting"),s.unselecting=!1,s.startselected=!1,i._trigger("unselected",t,{unselected:s.element})}),e(".ui-selecting",this.element[0]).each(function(){var s=e.data(this,"selectable-item");s.$element.removeClass("ui-selecting").addClass("ui-selected"),s.selecting=!1,s.selected=!0,s.startselected=!0,i._trigger("selected",t,{selected:s.element})}),this._trigger("stop",t),this.helper.remove(),!1}})})(jQuery);(function(t){function e(t,e,i){return t>e&&e+i>t}function i(t){return/left|right/.test(t.css("float"))||/inline|table-cell/.test(t.css("display"))}t.widget("ui.sortable",t.ui.mouse,{version:"1.10.2",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_create:function(){var t=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?"x"===t.axis||i(this.items[0].item):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var t=this.items.length-1;t>=0;t--)this.items[t].item.removeData(this.widgetName+"-item");return this},_setOption:function(e,i){"disabled"===e?(this.options[e]=i,this.widget().toggleClass("ui-sortable-disabled",!!i)):t.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(e,i){var s=null,n=!1,a=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(e),t(e.target).parents().each(function(){return t.data(this,a.widgetName+"-item")===a?(s=t(this),!1):undefined}),t.data(e.target,a.widgetName+"-item")===a&&(s=t(e.target)),s?!this.options.handle||i||(t(this.options.handle,s).find("*").addBack().each(function(){this===e.target&&(n=!0)}),n)?(this.currentItem=s,this._removeCurrentsFromItems(),!0):!1:!1)},_mouseStart:function(e,i,s){var n,a,o=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(e),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},t.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(e),this.originalPageX=e.pageX,this.originalPageY=e.pageY,o.cursorAt&&this._adjustOffsetFromHelper(o.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),o.containment&&this._setContainment(),o.cursor&&"auto"!==o.cursor&&(a=this.document.find("body"),this.storedCursor=a.css("cursor"),a.css("cursor",o.cursor),this.storedStylesheet=t("").appendTo(a)),o.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",o.opacity)),o.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",o.zIndex)),this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",e,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(n=this.containers.length-1;n>=0;n--)this.containers[n]._trigger("activate",e,this._uiHash(this));return t.ui.ddmanager&&(t.ui.ddmanager.current=this),t.ui.ddmanager&&!o.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(e),!0},_mouseDrag:function(e){var i,s,n,a,o=this.options,r=!1;for(this.position=this._generatePosition(e),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-e.pageY=0;i--)if(s=this.items[i],n=s.item[0],a=this._intersectsWithPointer(s),a&&s.instance===this.currentContainer&&n!==this.currentItem[0]&&this.placeholder[1===a?"next":"prev"]()[0]!==n&&!t.contains(this.placeholder[0],n)&&("semi-dynamic"===this.options.type?!t.contains(this.element[0],n):!0)){if(this.direction=1===a?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break;this._rearrange(e,s),this._trigger("change",e,this._uiHash());break}return this._contactContainers(e),t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),this._trigger("sort",e,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(e,i){if(e){if(t.ui.ddmanager&&!this.options.dropBehaviour&&t.ui.ddmanager.drop(this,e),this.options.revert){var s=this,n=this.placeholder.offset(),a=this.options.axis,o={};a&&"x"!==a||(o.left=n.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollLeft)),a&&"y"!==a||(o.top=n.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,t(this.helper).animate(o,parseInt(this.options.revert,10)||500,function(){s._clear(e)})}else this._clear(e,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp({target:null}),"original"===this.options.helper?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var e=this.containers.length-1;e>=0;e--)this.containers[e]._trigger("deactivate",null,this._uiHash(this)),this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",null,this._uiHash(this)),this.containers[e].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),t.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?t(this.domPosition.prev).after(this.currentItem):t(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},t(i).each(function(){var i=(t(e.item||this).attr(e.attribute||"id")||"").match(e.expression||/(.+)[\-=_](.+)/);i&&s.push((e.key||i[1]+"[]")+"="+(e.key&&e.expression?i[1]:i[2]))}),!s.length&&e.key&&s.push(e.key+"="),s.join("&")},toArray:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},i.each(function(){s.push(t(e.item||this).attr(e.attribute||"id")||"")}),s},_intersectsWith:function(t){var e=this.positionAbs.left,i=e+this.helperProportions.width,s=this.positionAbs.top,n=s+this.helperProportions.height,a=t.left,o=a+t.width,r=t.top,h=r+t.height,l=this.offset.click.top,c=this.offset.click.left,u=s+l>r&&h>s+l&&e+c>a&&o>e+c;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>t[this.floating?"width":"height"]?u:e+this.helperProportions.width/2>a&&o>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>r&&h>n-this.helperProportions.height/2},_intersectsWithPointer:function(t){var i="x"===this.options.axis||e(this.positionAbs.top+this.offset.click.top,t.top,t.height),s="y"===this.options.axis||e(this.positionAbs.left+this.offset.click.left,t.left,t.width),n=i&&s,a=this._getDragVerticalDirection(),o=this._getDragHorizontalDirection();return n?this.floating?o&&"right"===o||"down"===a?2:1:a&&("down"===a?2:1):!1},_intersectsWithSides:function(t){var i=e(this.positionAbs.top+this.offset.click.top,t.top+t.height/2,t.height),s=e(this.positionAbs.left+this.offset.click.left,t.left+t.width/2,t.width),n=this._getDragVerticalDirection(),a=this._getDragHorizontalDirection();return this.floating&&a?"right"===a&&s||"left"===a&&!s:n&&("down"===n&&i||"up"===n&&!i)},_getDragVerticalDirection:function(){var t=this.positionAbs.top-this.lastPositionAbs.top;return 0!==t&&(t>0?"down":"up")},_getDragHorizontalDirection:function(){var t=this.positionAbs.left-this.lastPositionAbs.left;return 0!==t&&(t>0?"right":"left")},refresh:function(t){return this._refreshItems(t),this.refreshPositions(),this},_connectWith:function(){var t=this.options;return t.connectWith.constructor===String?[t.connectWith]:t.connectWith},_getItemsAsjQuery:function(e){var i,s,n,a,o=[],r=[],h=this._connectWith();if(h&&e)for(i=h.length-1;i>=0;i--)for(n=t(h[i]),s=n.length-1;s>=0;s--)a=t.data(n[s],this.widgetFullName),a&&a!==this&&!a.options.disabled&&r.push([t.isFunction(a.options.items)?a.options.items.call(a.element):t(a.options.items,a.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),a]);for(r.push([t.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):t(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),i=r.length-1;i>=0;i--)r[i][0].each(function(){o.push(this)});return t(o)},_removeCurrentsFromItems:function(){var e=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=t.grep(this.items,function(t){for(var i=0;e.length>i;i++)if(e[i]===t.item[0])return!1;return!0})},_refreshItems:function(e){this.items=[],this.containers=[this];var i,s,n,a,o,r,h,l,c=this.items,u=[[t.isFunction(this.options.items)?this.options.items.call(this.element[0],e,{item:this.currentItem}):t(this.options.items,this.element),this]],d=this._connectWith();if(d&&this.ready)for(i=d.length-1;i>=0;i--)for(n=t(d[i]),s=n.length-1;s>=0;s--)a=t.data(n[s],this.widgetFullName),a&&a!==this&&!a.options.disabled&&(u.push([t.isFunction(a.options.items)?a.options.items.call(a.element[0],e,{item:this.currentItem}):t(a.options.items,a.element),a]),this.containers.push(a));for(i=u.length-1;i>=0;i--)for(o=u[i][1],r=u[i][0],s=0,l=r.length;l>s;s++)h=t(r[s]),h.data(this.widgetName+"-item",o),c.push({item:h,instance:o,width:0,height:0,left:0,top:0})},refreshPositions:function(e){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,n,a;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(n=this.options.toleranceElement?t(this.options.toleranceElement,s.item):s.item,e||(s.width=n.outerWidth(),s.height=n.outerHeight()),a=n.offset(),s.left=a.left,s.top=a.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)a=this.containers[i].element.offset(),this.containers[i].containerCache.left=a.left,this.containers[i].containerCache.top=a.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(e){e=e||this;var i,s=e.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=e.currentItem[0].nodeName.toLowerCase(),n=t(e.document[0].createElement(s)).addClass(i||e.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper");return"tr"===s?n.append(" "):"img"===s&&n.attr("src",e.currentItem.attr("src")),i||n.css("visibility","hidden"),n},update:function(t,n){(!i||s.forcePlaceholderSize)&&(n.height()||n.height(e.currentItem.innerHeight()-parseInt(e.currentItem.css("paddingTop")||0,10)-parseInt(e.currentItem.css("paddingBottom")||0,10)),n.width()||n.width(e.currentItem.innerWidth()-parseInt(e.currentItem.css("paddingLeft")||0,10)-parseInt(e.currentItem.css("paddingRight")||0,10)))}}),e.placeholder=t(s.placeholder.element.call(e.element,e.currentItem)),e.currentItem.after(e.placeholder),s.placeholder.update(e,e.placeholder)},_contactContainers:function(s){var n,a,o,r,h,l,c,u,d,p,f=null,m=null;for(n=this.containers.length-1;n>=0;n--)if(!t.contains(this.currentItem[0],this.containers[n].element[0]))if(this._intersectsWith(this.containers[n].containerCache)){if(f&&t.contains(this.containers[n].element[0],f.element[0]))continue;f=this.containers[n],m=n}else this.containers[n].containerCache.over&&(this.containers[n]._trigger("out",s,this._uiHash(this)),this.containers[n].containerCache.over=0);if(f)if(1===this.containers.length)this.containers[m].containerCache.over||(this.containers[m]._trigger("over",s,this._uiHash(this)),this.containers[m].containerCache.over=1);else{for(o=1e4,r=null,p=f.floating||i(this.currentItem),h=p?"left":"top",l=p?"width":"height",c=this.positionAbs[h]+this.offset.click[h],a=this.items.length-1;a>=0;a--)t.contains(this.containers[m].element[0],this.items[a].item[0])&&this.items[a].item[0]!==this.currentItem[0]&&(!p||e(this.positionAbs.top+this.offset.click.top,this.items[a].top,this.items[a].height))&&(u=this.items[a].item.offset()[h],d=!1,Math.abs(u-c)>Math.abs(u+this.items[a][l]-c)&&(d=!0,u+=this.items[a][l]),o>Math.abs(u-c)&&(o=Math.abs(u-c),r=this.items[a],this.direction=d?"up":"down"));if(!r&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[m])return;r?this._rearrange(s,r,null,!0):this._rearrange(s,null,this.containers[m].element,!0),this._trigger("change",s,this._uiHash()),this.containers[m]._trigger("change",s,this._uiHash(this)),this.currentContainer=this.containers[m],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[m]._trigger("over",s,this._uiHash(this)),this.containers[m].containerCache.over=1}},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper)?t(i.helper.apply(this.element[0],[e,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||t("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var e=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&t.ui.ie)&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var t=this.currentItem.position();return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:t.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options;"parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,t("document"===n.containment?document:window).width()-this.helperProportions.width-this.margins.left,(t("document"===n.containment?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||(e=t(n.containment)[0],i=t(n.containment).offset(),s="hidden"!==t(e).css("overflow"),this.containment=[i.left+(parseInt(t(e).css("borderLeftWidth"),10)||0)+(parseInt(t(e).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(t(e).css("borderTopWidth"),10)||0)+(parseInt(t(e).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(e.scrollWidth,e.offsetWidth):e.offsetWidth)-(parseInt(t(e).css("borderLeftWidth"),10)||0)-(parseInt(t(e).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(e.scrollHeight,e.offsetHeight):e.offsetHeight)-(parseInt(t(e).css("borderTopWidth"),10)||0)-(parseInt(t(e).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(e,i){i||(i=this.position);var s="absolute"===e?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,a=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():a?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():a?0:n.scrollLeft())*s}},_generatePosition:function(e){var i,s,n=this.options,a=e.pageX,o=e.pageY,r="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(r[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==document&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(e.pageX-this.offset.click.leftthis.containment[2]&&(a=this.containment[2]+this.offset.click.left),e.pageY-this.offset.click.top>this.containment[3]&&(o=this.containment[3]+this.offset.click.top)),n.grid&&(i=this.originalPageY+Math.round((o-this.originalPageY)/n.grid[1])*n.grid[1],o=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-n.grid[1]:i+n.grid[1]:i,s=this.originalPageX+Math.round((a-this.originalPageX)/n.grid[0])*n.grid[0],a=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-n.grid[0]:s+n.grid[0]:s)),{top:o-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:r.scrollTop()),left:a-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:r.scrollLeft())}},_rearrange:function(t,e,i,s){i?i[0].appendChild(this.placeholder[0]):e.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?e.item[0]:e.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var n=this.counter;this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(t,e){this.reverting=!1;var i,s=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(i in this._storedCSS)("auto"===this._storedCSS[i]||"static"===this._storedCSS[i])&&(this._storedCSS[i]="");this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!e&&s.push(function(t){this._trigger("receive",t,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||e||s.push(function(t){this._trigger("update",t,this._uiHash())}),this!==this.currentContainer&&(e||(s.push(function(t){this._trigger("remove",t,this._uiHash())}),s.push(function(t){return function(e){t._trigger("receive",e,this._uiHash(this))}}.call(this,this.currentContainer)),s.push(function(t){return function(e){t._trigger("update",e,this._uiHash(this))}}.call(this,this.currentContainer)))),i=this.containers.length-1;i>=0;i--)e||s.push(function(t){return function(e){t._trigger("deactivate",e,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over&&(s.push(function(t){return function(e){t._trigger("out",e,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,this.cancelHelperRemoval){if(!e){for(this._trigger("beforeStop",t,this._uiHash()),i=0;s.length>i;i++)s[i].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!1}if(e||this._trigger("beforeStop",t,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null,!e){for(i=0;s.length>i;i++)s[i].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!0},_trigger:function(){t.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(e){var i=e||this;return{helper:i.helper,placeholder:i.placeholder||t([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:e?e.element:null}}})})(jQuery);(function(t){var e=0,i={},s={};i.height=i.paddingTop=i.paddingBottom=i.borderTopWidth=i.borderBottomWidth="hide",s.height=s.paddingTop=s.paddingBottom=s.borderTopWidth=s.borderBottomWidth="show",t.widget("ui.accordion",{version:"1.10.2",options:{active:0,animate:{},collapsible:!1,event:"click",header:"> li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},_create:function(){var e=this.options;this.prevShow=this.prevHide=t(),this.element.addClass("ui-accordion ui-widget ui-helper-reset").attr("role","tablist"),e.collapsible||e.active!==!1&&null!=e.active||(e.active=0),this._processPanels(),0>e.active&&(e.active+=this.headers.length),this._refresh()},_getCreateEventData:function(){return{header:this.active,panel:this.active.length?this.active.next():t(),content:this.active.length?this.active.next():t()}},_createIcons:function(){var e=this.options.icons;e&&(t("").addClass("ui-accordion-header-icon ui-icon "+e.header).prependTo(this.headers),this.active.children(".ui-accordion-header-icon").removeClass(e.header).addClass(e.activeHeader),this.headers.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.removeClass("ui-accordion-icons").children(".ui-accordion-header-icon").remove()},_destroy:function(){var t;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.removeClass("ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-selected").removeAttr("aria-controls").removeAttr("tabIndex").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),this._destroyIcons(),t=this.headers.next().css("display","").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),"content"!==this.options.heightStyle&&t.css("height","")},_setOption:function(t,e){return"active"===t?(this._activate(e),undefined):("event"===t&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(e)),this._super(t,e),"collapsible"!==t||e||this.options.active!==!1||this._activate(0),"icons"===t&&(this._destroyIcons(),e&&this._createIcons()),"disabled"===t&&this.headers.add(this.headers.next()).toggleClass("ui-state-disabled",!!e),undefined)},_keydown:function(e){if(!e.altKey&&!e.ctrlKey){var i=t.ui.keyCode,s=this.headers.length,n=this.headers.index(e.target),a=!1;switch(e.keyCode){case i.RIGHT:case i.DOWN:a=this.headers[(n+1)%s];break;case i.LEFT:case i.UP:a=this.headers[(n-1+s)%s];break;case i.SPACE:case i.ENTER:this._eventHandler(e);break;case i.HOME:a=this.headers[0];break;case i.END:a=this.headers[s-1]}a&&(t(e.target).attr("tabIndex",-1),t(a).attr("tabIndex",0),a.focus(),e.preventDefault())}},_panelKeyDown:function(e){e.keyCode===t.ui.keyCode.UP&&e.ctrlKey&&t(e.currentTarget).prev().focus()},refresh:function(){var e=this.options;this._processPanels(),(e.active===!1&&e.collapsible===!0||!this.headers.length)&&(e.active=!1,this.active=t()),e.active===!1?this._activate(0):this.active.length&&!t.contains(this.element[0],this.active[0])?this.headers.length===this.headers.find(".ui-state-disabled").length?(e.active=!1,this.active=t()):this._activate(Math.max(0,e.active-1)):e.active=this.headers.index(this.active),this._destroyIcons(),this._refresh()},_processPanels:function(){this.headers=this.element.find(this.options.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all"),this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").filter(":not(.ui-accordion-content-active)").hide()},_refresh:function(){var i,s=this.options,n=s.heightStyle,a=this.element.parent(),o=this.accordionId="ui-accordion-"+(this.element.attr("id")||++e);this.active=this._findActive(s.active).addClass("ui-accordion-header-active ui-state-active ui-corner-top").removeClass("ui-corner-all"),this.active.next().addClass("ui-accordion-content-active").show(),this.headers.attr("role","tab").each(function(e){var i=t(this),s=i.attr("id"),n=i.next(),a=n.attr("id");s||(s=o+"-header-"+e,i.attr("id",s)),a||(a=o+"-panel-"+e,n.attr("id",a)),i.attr("aria-controls",a),n.attr("aria-labelledby",s)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false",tabIndex:-1}).next().attr({"aria-expanded":"false","aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true",tabIndex:0}).next().attr({"aria-expanded":"true","aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._createIcons(),this._setupEvents(s.event),"fill"===n?(i=a.height(),this.element.siblings(":visible").each(function(){var e=t(this),s=e.css("position");"absolute"!==s&&"fixed"!==s&&(i-=e.outerHeight(!0))}),this.headers.each(function(){i-=t(this).outerHeight(!0)}),this.headers.next().each(function(){t(this).height(Math.max(0,i-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===n&&(i=0,this.headers.next().each(function(){i=Math.max(i,t(this).css("height","").height())}).height(i))},_activate:function(e){var i=this._findActive(e)[0];i!==this.active[0]&&(i=i||this.active[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return"number"==typeof e?this.headers.eq(e):t()},_setupEvents:function(e){var i={keydown:"_keydown"};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.headers.add(this.headers.next())),this._on(this.headers,i),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._hoverable(this.headers),this._focusable(this.headers)},_eventHandler:function(e){var i=this.options,s=this.active,n=t(e.currentTarget),a=n[0]===s[0],o=a&&i.collapsible,r=o?t():n.next(),h=s.next(),l={oldHeader:s,oldPanel:h,newHeader:o?t():n,newPanel:r};e.preventDefault(),a&&!i.collapsible||this._trigger("beforeActivate",e,l)===!1||(i.active=o?!1:this.headers.index(n),this.active=a?t():n,this._toggle(l),s.removeClass("ui-accordion-header-active ui-state-active"),i.icons&&s.children(".ui-accordion-header-icon").removeClass(i.icons.activeHeader).addClass(i.icons.header),a||(n.removeClass("ui-corner-all").addClass("ui-accordion-header-active ui-state-active ui-corner-top"),i.icons&&n.children(".ui-accordion-header-icon").removeClass(i.icons.header).addClass(i.icons.activeHeader),n.next().addClass("ui-accordion-content-active")))},_toggle:function(e){var i=e.newPanel,s=this.prevShow.length?this.prevShow:e.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=i,this.prevHide=s,this.options.animate?this._animate(i,s,e):(s.hide(),i.show(),this._toggleComplete(e)),s.attr({"aria-expanded":"false","aria-hidden":"true"}),s.prev().attr("aria-selected","false"),i.length&&s.length?s.prev().attr("tabIndex",-1):i.length&&this.headers.filter(function(){return 0===t(this).attr("tabIndex")}).attr("tabIndex",-1),i.attr({"aria-expanded":"true","aria-hidden":"false"}).prev().attr({"aria-selected":"true",tabIndex:0})},_animate:function(t,e,n){var a,o,r,h=this,l=0,c=t.length&&(!e.length||t.index()",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},pending:0,_create:function(){var t,i,s,n=this.element[0].nodeName.toLowerCase(),a="textarea"===n,o="input"===n;this.isMultiLine=a?!0:o?!1:this.element.prop("isContentEditable"),this.valueMethod=this.element[a||o?"val":"text"],this.isNewMenu=!0,this.element.addClass("ui-autocomplete-input").attr("autocomplete","off"),this._on(this.element,{keydown:function(n){if(this.element.prop("readOnly"))return t=!0,s=!0,i=!0,undefined;t=!1,s=!1,i=!1;var a=e.ui.keyCode;switch(n.keyCode){case a.PAGE_UP:t=!0,this._move("previousPage",n);break;case a.PAGE_DOWN:t=!0,this._move("nextPage",n);break;case a.UP:t=!0,this._keyEvent("previous",n);break;case a.DOWN:t=!0,this._keyEvent("next",n);break;case a.ENTER:case a.NUMPAD_ENTER:this.menu.active&&(t=!0,n.preventDefault(),this.menu.select(n));break;case a.TAB:this.menu.active&&this.menu.select(n);break;case a.ESCAPE:this.menu.element.is(":visible")&&(this._value(this.term),this.close(n),n.preventDefault());break;default:i=!0,this._searchTimeout(n)}},keypress:function(s){if(t)return t=!1,s.preventDefault(),undefined;if(!i){var n=e.ui.keyCode;switch(s.keyCode){case n.PAGE_UP:this._move("previousPage",s);break;case n.PAGE_DOWN:this._move("nextPage",s);break;case n.UP:this._keyEvent("previous",s);break;case n.DOWN:this._keyEvent("next",s)}}},input:function(e){return s?(s=!1,e.preventDefault(),undefined):(this._searchTimeout(e),undefined)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(e){return this.cancelBlur?(delete this.cancelBlur,undefined):(clearTimeout(this.searching),this.close(e),this._change(e),undefined)}}),this._initSource(),this.menu=e("