deploiement sur VM
This commit is contained in:
@@ -1,17 +0,0 @@
|
|||||||
<VirtualHost *:{{ http_port }}>
|
|
||||||
ServerAdmin webmaster@localhost
|
|
||||||
ServerName {{ http_host }}
|
|
||||||
ServerAlias www.{{ http_host }}
|
|
||||||
DocumentRoot /var/www/{{ http_host }}
|
|
||||||
ErrorLog ${APACHE_LOG_DIR}/error.log
|
|
||||||
CustomLog ${APACHE_LOG_DIR}/access.log combined
|
|
||||||
|
|
||||||
<Directory /var/www/{{ http_host }}>
|
|
||||||
Options -Indexes
|
|
||||||
</Directory>
|
|
||||||
|
|
||||||
<IfModule mod_dir.c>
|
|
||||||
DirectoryIndex index.php index.html index.cgi index.pl index.xhtml index.htm
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
</VirtualHost>
|
|
||||||
@@ -3,12 +3,13 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: ..
|
context: ..
|
||||||
dockerfile: dockerfiles/front/Dockerfile
|
dockerfile: dockerfiles/front/Dockerfile
|
||||||
|
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
volumes:
|
volumes:
|
||||||
- ../../../doodlestudent/front:/app
|
- ../doodlestudent/front:/app
|
||||||
- ./certbot/www:/var/www/certbot:ro
|
- ../certbot/www:/var/www/certbot:ro
|
||||||
- ./certbot/conf:/etc/letsencrypt:ro
|
- ../certbot/conf:/etc/letsencrypt:ro
|
||||||
environment:
|
environment:
|
||||||
- FLASK_ENV=development
|
- FLASK_ENV=development
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -20,14 +21,14 @@ services:
|
|||||||
- app-network
|
- app-network
|
||||||
|
|
||||||
# https://stackoverflow.com/questions/57591868/how-correctly-install-ssl-certificate-using-certbot-in-docker
|
# https://stackoverflow.com/questions/57591868/how-correctly-install-ssl-certificate-using-certbot-in-docker
|
||||||
certbot:
|
# certbot:
|
||||||
image: certbot/certbot:latest
|
# image: certbot/certbot:latest
|
||||||
container_name: certbot
|
# container_name: certbot
|
||||||
depends_on:
|
# depends_on:
|
||||||
- front
|
# - front
|
||||||
volumes:
|
# volumes:
|
||||||
- ../certbot/www/:/var/www/certbot/:rw
|
# - ../certbot/www/:/var/www/certbot/:rw
|
||||||
- ../certbot/conf/:/etc/letsencrypt/:rw
|
# - ../certbot/conf/:/etc/letsencrypt/:rw
|
||||||
|
|
||||||
back:
|
back:
|
||||||
build:
|
build:
|
||||||
@@ -36,7 +37,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- ../../../doodlestudent/api:/app
|
- ../doodlestudent/api:/app
|
||||||
environment:
|
environment:
|
||||||
- FLASK_ENV=development
|
- FLASK_ENV=development
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -71,7 +72,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "9001:9001"
|
- "9001:9001"
|
||||||
volumes:
|
volumes:
|
||||||
- ../../../doodlestudent/api/APIKEY.txt:/opt/etherpad-lite/APIKEY.txt
|
- ../doodlestudent/api/APIKEY.txt:/opt/etherpad-lite/APIKEY.txt
|
||||||
networks:
|
networks:
|
||||||
- app-network
|
- app-network
|
||||||
healthcheck:
|
healthcheck:
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ WORKDIR /app
|
|||||||
RUN ./mvnw dependency:resolve
|
RUN ./mvnw dependency:resolve
|
||||||
|
|
||||||
COPY doodlestudent/api/src /app/src
|
COPY doodlestudent/api/src /app/src
|
||||||
RUN ./mvnw package -Pnative -DskipTests
|
RUN ./mvnw package -Pnative -DskipTests -Dquarkus.native.builder-opportunities=2 -Dquarkus.native.native-image-xmx=3g
|
||||||
|
|
||||||
RUN ls -l target
|
RUN ls -l target
|
||||||
|
|
||||||
|
|||||||
22
ansible/files/doodlestudent/README.french.md
Normal file
22
ansible/files/doodlestudent/README.french.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Doodle in quarkus
|
||||||
|
|
||||||
|
Ce repository est une application de type doodle développée avec quarkus.io pour le back et angular pour le front.
|
||||||
|
|
||||||
|
Elle initialise automatiquement un pad pour la réunion et un salon de discussion.
|
||||||
|
|
||||||
|
Le but est de faire travailler les étudiants sur la partie déploiement de ce type d'application dite cloud native.
|
||||||
|
|
||||||
|
Votre mission est de mettre en production une telle application en permettant
|
||||||
|
- qu'à chaque commit sur ce repository, si les tests passent, alors nous déployons automatiquement une nouvelle version dans un contexte (Continuous Deployement)
|
||||||
|
- que l'application doit être monitorer finement.
|
||||||
|
- que l'application redémarre automatiquement en cas de crash du serveur ou de crash d'un des services de l'application.
|
||||||
|
- que Les accès doivent http doivent utiliser https.
|
||||||
|
|
||||||
|
|
||||||
|
Une démo de l'application est accessible [ici](https://doodle.diverse-team.fr).
|
||||||
|
|
||||||
|
- Voici une petite [vidéo](https://drive.google.com/file/d/1GQbdgq2CHcddTlcoHqM5Zc8Dw5o_eeLg/preview) de présentation des fonctionnalités de l'application.
|
||||||
|
- Voici une petite [vidéo](https://drive.google.com/file/d/1l5UAsU5_q-oshwEW6edZ4UvQjN3-tzwi/preview) de présentation de l'architecture de l'application.
|
||||||
|
- Voici une petite [vidéo](https://drive.google.com/file/d/1jxYNfJdtd4r_pDbOthra360ei8Z17tX_/preview) de revue de code de l'application.
|
||||||
|
|
||||||
|
Un descriptif du cours, des TPs et des étapes du projet est lui accessible [ici](https://hackmd.diverse-team.fr/s/SJqu5DjSD)
|
||||||
15
ansible/files/doodlestudent/Readme.md
Normal file
15
ansible/files/doodlestudent/Readme.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Remote meetings planning
|
||||||
|
|
||||||
|
This project is used in a course on the *ops* part at the [University of Rennes](https://www.univ-rennes1.fr/), France. It is a kind of doodle clone developed in so-called "native cloud" technologies in order to allow students to work on a continuous deployment chain in a containerized environment. Among the feature, the application automatically initializes a pad for the meeting and a chat room for the meeting participants.
|
||||||
|
|
||||||
|
- The [back](https://github.com/barais/doodlestudent/tree/main/api) is developed using the [quarkus.io](https://quarkus.io/) framework.
|
||||||
|
- The [front](https://github.com/barais/doodlestudent/tree/main/front) is developed in [angular](https://angular.io/) using the [primeng](https://www.primefaces.org/primeng/) angular UI component library and the [fullcalendar](https://fullcalendar.io/) graphical component.
|
||||||
|
|
||||||
|
A demo of the application is available [here](https://doodle.diverse-team.fr/).
|
||||||
|
|
||||||
|
Three videos (in french) are available. They present:
|
||||||
|
- the [main application feature](https://drive.google.com/file/d/1GQbdgq2CHcddTlcoHqM5Zc8Dw5o_eeLg/preview),
|
||||||
|
- its [architecture](https://drive.google.com/file/d/1l5UAsU5_q-oshwEW6edZ4UvQjN3-tzwi/preview)
|
||||||
|
- and a [short code review](https://drive.google.com/file/d/1jxYNfJdtd4r_pDbOthra360ei8Z17tX_/preview) .
|
||||||
|
|
||||||
|
For french native speaker that wants to follow the course. The course web page is available [here](https://hackmd.diverse-team.fr/s/SJqu5DjSD).
|
||||||
1
ansible/files/doodlestudent/api/.dockerignore
Normal file
1
ansible/files/doodlestudent/api/.dockerignore
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
37
ansible/files/doodlestudent/api/.gitignore
vendored
Normal file
37
ansible/files/doodlestudent/api/.gitignore
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#Maven
|
||||||
|
target/
|
||||||
|
pom.xml.tag
|
||||||
|
pom.xml.releaseBackup
|
||||||
|
pom.xml.versionsBackup
|
||||||
|
release.properties
|
||||||
|
.mvn/wrapper/maven-wrapper.jar
|
||||||
|
# Eclipse
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.settings/
|
||||||
|
bin/
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
.idea
|
||||||
|
*.ipr
|
||||||
|
*.iml
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# NetBeans
|
||||||
|
nb-configuration.xml
|
||||||
|
|
||||||
|
# Visual Studio Code
|
||||||
|
.vscode
|
||||||
|
.factorypath
|
||||||
|
|
||||||
|
# OSX
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Vim
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
|
# patch
|
||||||
|
*.orig
|
||||||
|
*.rej
|
||||||
|
|
||||||
18
ansible/files/doodlestudent/api/.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
18
ansible/files/doodlestudent/api/.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you under the Apache License, Version 2.0 (the
|
||||||
|
# "License"); you may not use this file except in compliance
|
||||||
|
# with the License. You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing,
|
||||||
|
# software distributed under the License is distributed on an
|
||||||
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
# KIND, either express or implied. See the License for the
|
||||||
|
# specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip
|
||||||
|
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
|
||||||
1
ansible/files/doodlestudent/api/APIKEY.txt
Normal file
1
ansible/files/doodlestudent/api/APIKEY.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
19d89ca52bc0fa4f19d6325464d9d7a032649b9fa68c111514627081e2784b4a
|
||||||
53
ansible/files/doodlestudent/api/README.md
Normal file
53
ansible/files/doodlestudent/api/README.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# code-with-quarkus project
|
||||||
|
|
||||||
|
This project uses Quarkus, the Supersonic Subatomic Java Framework.
|
||||||
|
|
||||||
|
If you want to learn more about Quarkus, please visit its website: https://quarkus.io/ .
|
||||||
|
|
||||||
|
## Running the application in dev mode
|
||||||
|
|
||||||
|
You can run your application in dev mode that enables live coding using:
|
||||||
|
```shell script
|
||||||
|
docker-compose up --detach
|
||||||
|
# Wait the correct start of the docker services and then
|
||||||
|
./mvnw compile quarkus:dev
|
||||||
|
```
|
||||||
|
|
||||||
|
To stop the application and its dependencies, type `ctrl+c` in the bash session and run `docker-compose down`.
|
||||||
|
|
||||||
|
## Packaging and running the application
|
||||||
|
|
||||||
|
The application can be packaged using:
|
||||||
|
```shell script
|
||||||
|
./mvnw package
|
||||||
|
```
|
||||||
|
It produces the `code-with-quarkus-1.0.0-SNAPSHOT-runner.jar` file in the `/target` directory.
|
||||||
|
Be aware that it’s not an _über-jar_ as the dependencies are copied into the `target/lib` directory.
|
||||||
|
If you want to build an _über-jar_, execute the following command:
|
||||||
|
```shell script
|
||||||
|
./mvnw clean package -Dquarkus.package.type=uber-jar
|
||||||
|
```
|
||||||
|
|
||||||
|
The application is now runnable using `java -jar target/code-with-quarkus-1.0.0-SNAPSHOT-runner.jar`.
|
||||||
|
|
||||||
|
## Creating a native executable
|
||||||
|
|
||||||
|
You can create a native executable using:
|
||||||
|
```shell script
|
||||||
|
./mvnw package -Pnative
|
||||||
|
```
|
||||||
|
|
||||||
|
Or, if you don't have GraalVM installed, you can run the native executable build in a container using:
|
||||||
|
```shell script
|
||||||
|
./mvnw package -Pnative -Dquarkus.native.container-build=true
|
||||||
|
```
|
||||||
|
|
||||||
|
You can then execute your native executable with: `./target/code-with-quarkus-1.0.0-SNAPSHOT-runner`
|
||||||
|
|
||||||
|
If you want to learn more about building native executables, please consult https://quarkus.io/guides/maven-tooling.html.
|
||||||
|
|
||||||
|
# RESTEasy JAX-RS
|
||||||
|
|
||||||
|
Guide: https://quarkus.io/guides/rest-json
|
||||||
|
|
||||||
|
|
||||||
22
ansible/files/doodlestudent/api/docker-compose.yaml
Normal file
22
ansible/files/doodlestudent/api/docker-compose.yaml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
version: "3.8"
|
||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: mysql
|
||||||
|
ports:
|
||||||
|
- "3306:3306"
|
||||||
|
environment:
|
||||||
|
- MYSQL_ROOT_PASSWORD=root
|
||||||
|
- MYSQL_DATABASE=tlc
|
||||||
|
- MYSQL_USER=tlc
|
||||||
|
- MYSQL_PASSWORD=tlc
|
||||||
|
etherpad:
|
||||||
|
image: etherpad/etherpad
|
||||||
|
ports:
|
||||||
|
- "9001:9001"
|
||||||
|
volumes:
|
||||||
|
- ./APIKEY.txt:/opt/etherpad-lite/APIKEY.txt
|
||||||
|
mail:
|
||||||
|
image: bytemark/smtp
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "2525:25"
|
||||||
308
ansible/files/doodlestudent/api/mvnw
vendored
Executable file
308
ansible/files/doodlestudent/api/mvnw
vendored
Executable file
@@ -0,0 +1,308 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you under the Apache License, Version 2.0 (the
|
||||||
|
# "License"); you may not use this file except in compliance
|
||||||
|
# with the License. You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing,
|
||||||
|
# software distributed under the License is distributed on an
|
||||||
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
# KIND, either express or implied. See the License for the
|
||||||
|
# specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Apache Maven Wrapper startup batch script, version 3.2.0
|
||||||
|
#
|
||||||
|
# Required ENV vars:
|
||||||
|
# ------------------
|
||||||
|
# JAVA_HOME - location of a JDK home dir
|
||||||
|
#
|
||||||
|
# Optional ENV vars
|
||||||
|
# -----------------
|
||||||
|
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||||
|
# e.g. to debug Maven itself, use
|
||||||
|
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||||
|
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||||
|
|
||||||
|
if [ -f /usr/local/etc/mavenrc ] ; then
|
||||||
|
. /usr/local/etc/mavenrc
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f /etc/mavenrc ] ; then
|
||||||
|
. /etc/mavenrc
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$HOME/.mavenrc" ] ; then
|
||||||
|
. "$HOME/.mavenrc"
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
# OS specific support. $var _must_ be set to either true or false.
|
||||||
|
cygwin=false;
|
||||||
|
darwin=false;
|
||||||
|
mingw=false
|
||||||
|
case "$(uname)" in
|
||||||
|
CYGWIN*) cygwin=true ;;
|
||||||
|
MINGW*) mingw=true;;
|
||||||
|
Darwin*) darwin=true
|
||||||
|
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||||
|
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||||
|
if [ -z "$JAVA_HOME" ]; then
|
||||||
|
if [ -x "/usr/libexec/java_home" ]; then
|
||||||
|
JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME
|
||||||
|
else
|
||||||
|
JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -z "$JAVA_HOME" ] ; then
|
||||||
|
if [ -r /etc/gentoo-release ] ; then
|
||||||
|
JAVA_HOME=$(java-config --jre-home)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||||
|
if $cygwin ; then
|
||||||
|
[ -n "$JAVA_HOME" ] &&
|
||||||
|
JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
|
||||||
|
[ -n "$CLASSPATH" ] &&
|
||||||
|
CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||||
|
if $mingw ; then
|
||||||
|
[ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] &&
|
||||||
|
JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$JAVA_HOME" ]; then
|
||||||
|
javaExecutable="$(which javac)"
|
||||||
|
if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then
|
||||||
|
# readlink(1) is not available as standard on Solaris 10.
|
||||||
|
readLink=$(which readlink)
|
||||||
|
if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then
|
||||||
|
if $darwin ; then
|
||||||
|
javaHome="$(dirname "\"$javaExecutable\"")"
|
||||||
|
javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac"
|
||||||
|
else
|
||||||
|
javaExecutable="$(readlink -f "\"$javaExecutable\"")"
|
||||||
|
fi
|
||||||
|
javaHome="$(dirname "\"$javaExecutable\"")"
|
||||||
|
javaHome=$(expr "$javaHome" : '\(.*\)/bin')
|
||||||
|
JAVA_HOME="$javaHome"
|
||||||
|
export JAVA_HOME
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$JAVACMD" ] ; then
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||||
|
echo " We cannot execute $JAVACMD" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$JAVA_HOME" ] ; then
|
||||||
|
echo "Warning: JAVA_HOME environment variable is not set."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# traverses directory structure from process work directory to filesystem root
|
||||||
|
# first directory with .mvn subdirectory is considered project base directory
|
||||||
|
find_maven_basedir() {
|
||||||
|
if [ -z "$1" ]
|
||||||
|
then
|
||||||
|
echo "Path not specified to find_maven_basedir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
basedir="$1"
|
||||||
|
wdir="$1"
|
||||||
|
while [ "$wdir" != '/' ] ; do
|
||||||
|
if [ -d "$wdir"/.mvn ] ; then
|
||||||
|
basedir=$wdir
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||||
|
if [ -d "${wdir}" ]; then
|
||||||
|
wdir=$(cd "$wdir/.." || exit 1; pwd)
|
||||||
|
fi
|
||||||
|
# end of workaround
|
||||||
|
done
|
||||||
|
printf '%s' "$(cd "$basedir" || exit 1; pwd)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# concatenates all lines of a file
|
||||||
|
concat_lines() {
|
||||||
|
if [ -f "$1" ]; then
|
||||||
|
# Remove \r in case we run on Windows within Git Bash
|
||||||
|
# and check out the repository with auto CRLF management
|
||||||
|
# enabled. Otherwise, we may read lines that are delimited with
|
||||||
|
# \r\n and produce $'-Xarg\r' rather than -Xarg due to word
|
||||||
|
# splitting rules.
|
||||||
|
tr -s '\r\n' ' ' < "$1"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
log() {
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
printf '%s\n' "$1"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
|
||||||
|
if [ -z "$BASE_DIR" ]; then
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
|
||||||
|
log "$MAVEN_PROJECTBASEDIR"
|
||||||
|
|
||||||
|
##########################################################################################
|
||||||
|
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||||
|
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||||
|
##########################################################################################
|
||||||
|
wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
|
||||||
|
if [ -r "$wrapperJarPath" ]; then
|
||||||
|
log "Found $wrapperJarPath"
|
||||||
|
else
|
||||||
|
log "Couldn't find $wrapperJarPath, downloading it ..."
|
||||||
|
|
||||||
|
if [ -n "$MVNW_REPOURL" ]; then
|
||||||
|
wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||||
|
else
|
||||||
|
wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||||
|
fi
|
||||||
|
while IFS="=" read -r key value; do
|
||||||
|
# Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
|
||||||
|
safeValue=$(echo "$value" | tr -d '\r')
|
||||||
|
case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;;
|
||||||
|
esac
|
||||||
|
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
log "Downloading from: $wrapperUrl"
|
||||||
|
|
||||||
|
if $cygwin; then
|
||||||
|
wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v wget > /dev/null; then
|
||||||
|
log "Found wget ... using wget"
|
||||||
|
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
|
||||||
|
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||||
|
wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||||
|
else
|
||||||
|
wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||||
|
fi
|
||||||
|
elif command -v curl > /dev/null; then
|
||||||
|
log "Found curl ... using curl"
|
||||||
|
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
|
||||||
|
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||||
|
curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
|
||||||
|
else
|
||||||
|
curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log "Falling back to using Java to download"
|
||||||
|
javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||||
|
javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
|
||||||
|
# For Cygwin, switch paths to Windows format before running javac
|
||||||
|
if $cygwin; then
|
||||||
|
javaSource=$(cygpath --path --windows "$javaSource")
|
||||||
|
javaClass=$(cygpath --path --windows "$javaClass")
|
||||||
|
fi
|
||||||
|
if [ -e "$javaSource" ]; then
|
||||||
|
if [ ! -e "$javaClass" ]; then
|
||||||
|
log " - Compiling MavenWrapperDownloader.java ..."
|
||||||
|
("$JAVA_HOME/bin/javac" "$javaSource")
|
||||||
|
fi
|
||||||
|
if [ -e "$javaClass" ]; then
|
||||||
|
log " - Running MavenWrapperDownloader.java ..."
|
||||||
|
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
##########################################################################################
|
||||||
|
# End of extension
|
||||||
|
##########################################################################################
|
||||||
|
|
||||||
|
# If specified, validate the SHA-256 sum of the Maven wrapper jar file
|
||||||
|
wrapperSha256Sum=""
|
||||||
|
while IFS="=" read -r key value; do
|
||||||
|
case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;;
|
||||||
|
esac
|
||||||
|
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
if [ -n "$wrapperSha256Sum" ]; then
|
||||||
|
wrapperSha256Result=false
|
||||||
|
if command -v sha256sum > /dev/null; then
|
||||||
|
if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then
|
||||||
|
wrapperSha256Result=true
|
||||||
|
fi
|
||||||
|
elif command -v shasum > /dev/null; then
|
||||||
|
if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then
|
||||||
|
wrapperSha256Result=true
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available."
|
||||||
|
echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ $wrapperSha256Result = false ]; then
|
||||||
|
echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
|
||||||
|
echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
|
||||||
|
echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||||
|
|
||||||
|
# For Cygwin, switch paths to Windows format before running java
|
||||||
|
if $cygwin; then
|
||||||
|
[ -n "$JAVA_HOME" ] &&
|
||||||
|
JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
|
||||||
|
[ -n "$CLASSPATH" ] &&
|
||||||
|
CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
|
||||||
|
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||||
|
MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Provide a "standardized" way to retrieve the CLI args that will
|
||||||
|
# work with both Windows and non-Windows executions.
|
||||||
|
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*"
|
||||||
|
export MAVEN_CMD_LINE_ARGS
|
||||||
|
|
||||||
|
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||||
|
|
||||||
|
# shellcheck disable=SC2086 # safe args
|
||||||
|
exec "$JAVACMD" \
|
||||||
|
$MAVEN_OPTS \
|
||||||
|
$MAVEN_DEBUG_OPTS \
|
||||||
|
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||||
|
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||||
|
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
||||||
205
ansible/files/doodlestudent/api/mvnw.cmd
vendored
Normal file
205
ansible/files/doodlestudent/api/mvnw.cmd
vendored
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
@REM or more contributor license agreements. See the NOTICE file
|
||||||
|
@REM distributed with this work for additional information
|
||||||
|
@REM regarding copyright ownership. The ASF licenses this file
|
||||||
|
@REM to you under the Apache License, Version 2.0 (the
|
||||||
|
@REM "License"); you may not use this file except in compliance
|
||||||
|
@REM with the License. You may obtain a copy of the License at
|
||||||
|
@REM
|
||||||
|
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@REM
|
||||||
|
@REM Unless required by applicable law or agreed to in writing,
|
||||||
|
@REM software distributed under the License is distributed on an
|
||||||
|
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
@REM KIND, either express or implied. See the License for the
|
||||||
|
@REM specific language governing permissions and limitations
|
||||||
|
@REM under the License.
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
@REM Apache Maven Wrapper startup batch script, version 3.2.0
|
||||||
|
@REM
|
||||||
|
@REM Required ENV vars:
|
||||||
|
@REM JAVA_HOME - location of a JDK home dir
|
||||||
|
@REM
|
||||||
|
@REM Optional ENV vars
|
||||||
|
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||||
|
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
|
||||||
|
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||||
|
@REM e.g. to debug Maven itself, use
|
||||||
|
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||||
|
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||||
|
@echo off
|
||||||
|
@REM set title of command window
|
||||||
|
title %0
|
||||||
|
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
|
||||||
|
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||||
|
|
||||||
|
@REM set %HOME% to equivalent of $HOME
|
||||||
|
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||||
|
|
||||||
|
@REM Execute a user defined script before this one
|
||||||
|
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||||
|
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||||
|
if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
|
||||||
|
if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
|
||||||
|
:skipRcPre
|
||||||
|
|
||||||
|
@setlocal
|
||||||
|
|
||||||
|
set ERROR_CODE=0
|
||||||
|
|
||||||
|
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||||
|
@setlocal
|
||||||
|
|
||||||
|
@REM ==== START VALIDATION ====
|
||||||
|
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo Error: JAVA_HOME not found in your environment. >&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||||
|
echo location of your Java installation. >&2
|
||||||
|
echo.
|
||||||
|
goto error
|
||||||
|
|
||||||
|
:OkJHome
|
||||||
|
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||||
|
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||||
|
echo location of your Java installation. >&2
|
||||||
|
echo.
|
||||||
|
goto error
|
||||||
|
|
||||||
|
@REM ==== END VALIDATION ====
|
||||||
|
|
||||||
|
:init
|
||||||
|
|
||||||
|
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||||
|
@REM Fallback to current working directory if not found.
|
||||||
|
|
||||||
|
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||||
|
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||||
|
|
||||||
|
set EXEC_DIR=%CD%
|
||||||
|
set WDIR=%EXEC_DIR%
|
||||||
|
:findBaseDir
|
||||||
|
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||||
|
cd ..
|
||||||
|
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||||
|
set WDIR=%CD%
|
||||||
|
goto findBaseDir
|
||||||
|
|
||||||
|
:baseDirFound
|
||||||
|
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||||
|
cd "%EXEC_DIR%"
|
||||||
|
goto endDetectBaseDir
|
||||||
|
|
||||||
|
:baseDirNotFound
|
||||||
|
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||||
|
cd "%EXEC_DIR%"
|
||||||
|
|
||||||
|
:endDetectBaseDir
|
||||||
|
|
||||||
|
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||||
|
|
||||||
|
@setlocal EnableExtensions EnableDelayedExpansion
|
||||||
|
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||||
|
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||||
|
|
||||||
|
:endReadAdditionalConfig
|
||||||
|
|
||||||
|
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||||
|
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||||
|
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||||
|
|
||||||
|
set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||||
|
|
||||||
|
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||||
|
IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
|
||||||
|
)
|
||||||
|
|
||||||
|
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||||
|
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||||
|
if exist %WRAPPER_JAR% (
|
||||||
|
if "%MVNW_VERBOSE%" == "true" (
|
||||||
|
echo Found %WRAPPER_JAR%
|
||||||
|
)
|
||||||
|
) else (
|
||||||
|
if not "%MVNW_REPOURL%" == "" (
|
||||||
|
SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||||
|
)
|
||||||
|
if "%MVNW_VERBOSE%" == "true" (
|
||||||
|
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||||
|
echo Downloading from: %WRAPPER_URL%
|
||||||
|
)
|
||||||
|
|
||||||
|
powershell -Command "&{"^
|
||||||
|
"$webclient = new-object System.Net.WebClient;"^
|
||||||
|
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
|
||||||
|
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
|
||||||
|
"}"^
|
||||||
|
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
|
||||||
|
"}"
|
||||||
|
if "%MVNW_VERBOSE%" == "true" (
|
||||||
|
echo Finished downloading %WRAPPER_JAR%
|
||||||
|
)
|
||||||
|
)
|
||||||
|
@REM End of extension
|
||||||
|
|
||||||
|
@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
|
||||||
|
SET WRAPPER_SHA_256_SUM=""
|
||||||
|
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||||
|
IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
|
||||||
|
)
|
||||||
|
IF NOT %WRAPPER_SHA_256_SUM%=="" (
|
||||||
|
powershell -Command "&{"^
|
||||||
|
"$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
|
||||||
|
"If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
|
||||||
|
" Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
|
||||||
|
" Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
|
||||||
|
" Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
|
||||||
|
" exit 1;"^
|
||||||
|
"}"^
|
||||||
|
"}"
|
||||||
|
if ERRORLEVEL 1 goto error
|
||||||
|
)
|
||||||
|
|
||||||
|
@REM Provide a "standardized" way to retrieve the CLI args that will
|
||||||
|
@REM work with both Windows and non-Windows executions.
|
||||||
|
set MAVEN_CMD_LINE_ARGS=%*
|
||||||
|
|
||||||
|
%MAVEN_JAVA_EXE% ^
|
||||||
|
%JVM_CONFIG_MAVEN_PROPS% ^
|
||||||
|
%MAVEN_OPTS% ^
|
||||||
|
%MAVEN_DEBUG_OPTS% ^
|
||||||
|
-classpath %WRAPPER_JAR% ^
|
||||||
|
"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
|
||||||
|
%WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
|
||||||
|
if ERRORLEVEL 1 goto error
|
||||||
|
goto end
|
||||||
|
|
||||||
|
:error
|
||||||
|
set ERROR_CODE=1
|
||||||
|
|
||||||
|
:end
|
||||||
|
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||||
|
|
||||||
|
if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
|
||||||
|
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||||
|
if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
|
||||||
|
if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
|
||||||
|
:skipRcPost
|
||||||
|
|
||||||
|
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||||
|
if "%MAVEN_BATCH_PAUSE%"=="on" pause
|
||||||
|
|
||||||
|
if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
|
||||||
|
|
||||||
|
cmd /C exit /B %ERROR_CODE%
|
||||||
266
ansible/files/doodlestudent/api/pom.xml
Normal file
266
ansible/files/doodlestudent/api/pom.xml
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>fr.istic</groupId>
|
||||||
|
<artifactId>tlcdemoApp</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
<properties>
|
||||||
|
<compiler-plugin.version>3.11.0</compiler-plugin.version>
|
||||||
|
<maven.compiler.release>17</maven.compiler.release>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
|
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
|
||||||
|
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
|
||||||
|
<quarkus.platform.version>3.7.1</quarkus.platform.version>
|
||||||
|
<skipITs>true</skipITs>
|
||||||
|
<surefire-plugin.version>3.0.0</surefire-plugin.version>
|
||||||
|
</properties>
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>${quarkus.platform.group-id}</groupId>
|
||||||
|
<artifactId>${quarkus.platform.artifact-id}</artifactId>
|
||||||
|
<version>${quarkus.platform.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-arc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-junit5</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.rest-assured</groupId>
|
||||||
|
<artifactId>rest-assured</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-hibernate-orm</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-config-yaml</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-hibernate-orm-rest-data-panache</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-resteasy</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-scheduler</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-jdbc-mysql</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-smallrye-metrics</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-smallrye-opentracing</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-hibernate-validator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-smallrye-openapi</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-jackson</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-resteasy-jackson</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-mailer</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-spring-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-flyway</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.sourceforge.jexcelapi</groupId>
|
||||||
|
<artifactId>jxl</artifactId>
|
||||||
|
<version>2.6.12</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.gjerull.etherpad</groupId>
|
||||||
|
<artifactId>etherpad_lite_client</artifactId>
|
||||||
|
<version>1.2.13</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.mnode.ical4j/ical4j -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mnode.ical4j</groupId>
|
||||||
|
<artifactId>ical4j</artifactId>
|
||||||
|
<version>3.0.20</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpasyncclient -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpasyncclient</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>commons-logging</groupId>
|
||||||
|
<artifactId>commons-logging</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/javax.cache/cache-api -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.cache</groupId>
|
||||||
|
<artifactId>cache-api</artifactId>
|
||||||
|
<version>1.1.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.jsr107.ri/cache-ri-impl -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jsr107.ri</groupId>
|
||||||
|
<artifactId>cache-ri-impl</artifactId>
|
||||||
|
<version>1.1.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.logging</groupId>
|
||||||
|
<artifactId>commons-logging-jboss-logging</artifactId>
|
||||||
|
<version>1.0.0.Final</version>
|
||||||
|
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.logmanager</groupId>
|
||||||
|
<artifactId>log4j-jboss-logmanager</artifactId>
|
||||||
|
<version>1.2.0.Final</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-jboss-logging</artifactId>
|
||||||
|
<version>1.2.1.Final</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.flywaydb</groupId>
|
||||||
|
<artifactId>flyway-mysql</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>${quarkus.platform.group-id}</groupId>
|
||||||
|
<artifactId>quarkus-maven-plugin</artifactId>
|
||||||
|
<version>${quarkus.platform.version}</version>
|
||||||
|
<extensions>true</extensions>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>build</goal>
|
||||||
|
<goal>generate-code</goal>
|
||||||
|
<goal>generate-code-tests</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>${compiler-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<compilerArgs>
|
||||||
|
<arg>-parameters</arg>
|
||||||
|
</compilerArgs>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>${surefire-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<systemPropertyVariables>
|
||||||
|
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
||||||
|
<maven.home>${maven.home}</maven.home>
|
||||||
|
</systemPropertyVariables>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-failsafe-plugin</artifactId>
|
||||||
|
<version>${surefire-plugin.version}</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>integration-test</goal>
|
||||||
|
<goal>verify</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<systemPropertyVariables>
|
||||||
|
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
|
||||||
|
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
||||||
|
<maven.home>${maven.home}</maven.home>
|
||||||
|
</systemPropertyVariables>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>native</id>
|
||||||
|
<activation>
|
||||||
|
<property>
|
||||||
|
<name>native</name>
|
||||||
|
</property>
|
||||||
|
</activation>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-failsafe-plugin</artifactId>
|
||||||
|
<version>${surefire-plugin.version}</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>integration-test</goal>
|
||||||
|
<goal>verify</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<systemPropertyVariables>
|
||||||
|
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
|
||||||
|
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
||||||
|
<maven.home>${maven.home}</maven.home>
|
||||||
|
</systemPropertyVariables>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<properties>
|
||||||
|
<quarkus.native.additional-build-args>--initialize-at-run-time=org.apache.http.impl.auth.NTLMEngineImpl,-H:ReflectionConfigurationFiles=reflection-config.json,-H:IncludeResourceBundles=sun.util.resources.TimeZoneNames</quarkus.native.additional-build-args>
|
||||||
|
<skipITs>false</skipITs>
|
||||||
|
<quarkus.package.type>native</quarkus.package.type>
|
||||||
|
</properties>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
####
|
||||||
|
# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
|
||||||
|
#
|
||||||
|
# Before building the container image run:
|
||||||
|
#
|
||||||
|
# ./mvnw package
|
||||||
|
#
|
||||||
|
# Then, build the image with:
|
||||||
|
#
|
||||||
|
# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/tlcdemoApp-jvm .
|
||||||
|
#
|
||||||
|
# Then run the container using:
|
||||||
|
#
|
||||||
|
# docker run -i --rm -p 8080:8080 quarkus/tlcdemoApp-jvm
|
||||||
|
#
|
||||||
|
# If you want to include the debug port into your docker image
|
||||||
|
# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005.
|
||||||
|
# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005
|
||||||
|
# when running the container
|
||||||
|
#
|
||||||
|
# Then run the container using :
|
||||||
|
#
|
||||||
|
# docker run -i --rm -p 8080:8080 quarkus/tlcdemoApp-jvm
|
||||||
|
#
|
||||||
|
# This image uses the `run-java.sh` script to run the application.
|
||||||
|
# This scripts computes the command line to execute your Java application, and
|
||||||
|
# includes memory/GC tuning.
|
||||||
|
# You can configure the behavior using the following environment properties:
|
||||||
|
# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class")
|
||||||
|
# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options
|
||||||
|
# in JAVA_OPTS (example: "-Dsome.property=foo")
|
||||||
|
# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is
|
||||||
|
# used to calculate a default maximal heap memory based on a containers restriction.
|
||||||
|
# If used in a container without any memory constraints for the container then this
|
||||||
|
# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio
|
||||||
|
# of the container available memory as set here. The default is `50` which means 50%
|
||||||
|
# of the available memory is used as an upper boundary. You can skip this mechanism by
|
||||||
|
# setting this value to `0` in which case no `-Xmx` option is added.
|
||||||
|
# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This
|
||||||
|
# is used to calculate a default initial heap memory based on the maximum heap memory.
|
||||||
|
# If used in a container without any memory constraints for the container then this
|
||||||
|
# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio
|
||||||
|
# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx`
|
||||||
|
# is used as the initial heap size. You can skip this mechanism by setting this value
|
||||||
|
# to `0` in which case no `-Xms` option is added (example: "25")
|
||||||
|
# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS.
|
||||||
|
# This is used to calculate the maximum value of the initial heap memory. If used in
|
||||||
|
# a container without any memory constraints for the container then this option has
|
||||||
|
# no effect. If there is a memory constraint then `-Xms` is limited to the value set
|
||||||
|
# here. The default is 4096MB which means the calculated value of `-Xms` never will
|
||||||
|
# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096")
|
||||||
|
# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output
|
||||||
|
# when things are happening. This option, if set to true, will set
|
||||||
|
# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true").
|
||||||
|
# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example:
|
||||||
|
# true").
|
||||||
|
# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787").
|
||||||
|
# - CONTAINER_CORE_LIMIT: A calculated core limit as described in
|
||||||
|
# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2")
|
||||||
|
# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024").
|
||||||
|
# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion.
|
||||||
|
# (example: "20")
|
||||||
|
# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking.
|
||||||
|
# (example: "40")
|
||||||
|
# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection.
|
||||||
|
# (example: "4")
|
||||||
|
# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus
|
||||||
|
# previous GC times. (example: "90")
|
||||||
|
# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20")
|
||||||
|
# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100")
|
||||||
|
# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should
|
||||||
|
# contain the necessary JRE command-line options to specify the required GC, which
|
||||||
|
# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC).
|
||||||
|
# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080")
|
||||||
|
# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080")
|
||||||
|
# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be
|
||||||
|
# accessed directly. (example: "foo.example.com,bar.example.com")
|
||||||
|
#
|
||||||
|
###
|
||||||
|
FROM registry.access.redhat.com/ubi8/openjdk-17:1.16
|
||||||
|
|
||||||
|
ENV LANGUAGE='en_US:en'
|
||||||
|
|
||||||
|
|
||||||
|
# We make four distinct layers so if there are application changes the library layers can be re-used
|
||||||
|
COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/
|
||||||
|
COPY --chown=185 target/quarkus-app/*.jar /deployments/
|
||||||
|
COPY --chown=185 target/quarkus-app/app/ /deployments/app/
|
||||||
|
COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
USER 185
|
||||||
|
ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
|
||||||
|
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
|
||||||
|
|
||||||
|
ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]
|
||||||
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
####
|
||||||
|
# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode
|
||||||
|
#
|
||||||
|
# Before building the container image run:
|
||||||
|
#
|
||||||
|
# mvn package -Pnative -Dquarkus.native.container-build=true
|
||||||
|
#
|
||||||
|
# Then, build the image with:
|
||||||
|
#
|
||||||
|
# docker build -f src/main/docker/Dockerfile.native -t barais/doodleback-with-quarkus .
|
||||||
|
#
|
||||||
|
# Then run the container using:
|
||||||
|
#
|
||||||
|
# docker run -i --rm -p 8080:8080 barais/doodleback-with-quarkus
|
||||||
|
#
|
||||||
|
###
|
||||||
|
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.8
|
||||||
|
WORKDIR /work/
|
||||||
|
RUN chown 1001 /work \
|
||||||
|
&& chmod "g+rwX" /work \
|
||||||
|
&& chown 1001:root /work
|
||||||
|
COPY --chown=1001:root target/*-runner /work/application
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
USER 1001
|
||||||
|
|
||||||
|
# ENV quarkus_datasource_jdbc_url "jdbc:mysql://db:3306/tlc?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true&serverTimezone=Europe/Paris"
|
||||||
|
# ENV quarkus_datasource_username tlc
|
||||||
|
# ENV quarkus_datasource_password tlc
|
||||||
|
# ENV quarkus_hibernate_orm_database_generation update
|
||||||
|
# ENV quarkus_mailer_from olivier.barais@gmail.com
|
||||||
|
# ENV quarkus_mailer_host localhost
|
||||||
|
# ENV quarkus_mailer_port 2525
|
||||||
|
# ENV quarkus_mailer_ssl false
|
||||||
|
# ENV quarkus_mailer_username ""
|
||||||
|
# ENV quarkus_mailer_password ""
|
||||||
|
# ENV quarkus_mailer_mock true
|
||||||
|
# ENV doodle_usepad false
|
||||||
|
# ENV doodle_padUrl http://etherpad:9001/
|
||||||
|
# ENV doodle_padApiKey "changeit"
|
||||||
|
# ENV doodle_organizermail "olivier.barais@gmail.com"
|
||||||
|
|
||||||
|
|
||||||
|
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package fr.istic.tlc.dao;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import fr.istic.tlc.domain.Choice;
|
||||||
|
import io.quarkus.hibernate.orm.panache.PanacheRepository;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class ChoiceRepository implements PanacheRepository<Choice> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package fr.istic.tlc.dao;
|
||||||
|
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
|
||||||
|
import fr.istic.tlc.domain.Comment;
|
||||||
|
import io.quarkus.hibernate.orm.panache.PanacheRepository;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class CommentRepository implements PanacheRepository<Comment> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package fr.istic.tlc.dao;
|
||||||
|
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
|
||||||
|
import fr.istic.tlc.domain.MealPreference;
|
||||||
|
import io.quarkus.hibernate.orm.panache.PanacheRepository;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class MealPreferenceRepository implements PanacheRepository<MealPreference> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package fr.istic.tlc.dao;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
|
||||||
|
import fr.istic.tlc.domain.Poll;
|
||||||
|
import fr.istic.tlc.domain.User;
|
||||||
|
import io.quarkus.hibernate.orm.panache.PanacheRepository;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class PollRepository implements PanacheRepository<Poll> {
|
||||||
|
|
||||||
|
public Poll findBySlug(String slug){
|
||||||
|
return find("slug", slug).firstResult();
|
||||||
|
}
|
||||||
|
public Poll findByAdminSlug(String slug){
|
||||||
|
return find("slugAdmin", slug).firstResult();
|
||||||
|
}
|
||||||
|
public List<User> findAllUser4Poll(long id){
|
||||||
|
return this.getEntityManager().createQuery("select distinct c.users from Poll p join p.pollChoices as c where p.id = ?1").setParameter(1, id).getResultList();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package fr.istic.tlc.dao;
|
||||||
|
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
|
||||||
|
import fr.istic.tlc.domain.User;
|
||||||
|
import io.quarkus.hibernate.orm.panache.PanacheRepository;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class UserRepository implements PanacheRepository<User> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
package fr.istic.tlc.domain;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.GenerationType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.JoinTable;
|
||||||
|
import jakarta.persistence.ManyToMany;
|
||||||
|
import jakarta.persistence.Temporal;
|
||||||
|
import jakarta.persistence.TemporalType;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class Choice {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
//private String name;
|
||||||
|
|
||||||
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
|
private Date startDate;
|
||||||
|
|
||||||
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
|
private Date endDate;
|
||||||
|
|
||||||
|
@ManyToMany
|
||||||
|
@JoinTable(
|
||||||
|
name = "choice_user",
|
||||||
|
joinColumns = @JoinColumn(name = "choice_id"),
|
||||||
|
inverseJoinColumns = @JoinColumn(name = "user_id"))
|
||||||
|
private List<User> users;
|
||||||
|
|
||||||
|
|
||||||
|
public Choice(){}
|
||||||
|
|
||||||
|
public Choice(Date startDate, Date endDate, List<User> users) {
|
||||||
|
this.startDate = startDate;
|
||||||
|
this.endDate = endDate;
|
||||||
|
this.users = users;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addUser(User user){
|
||||||
|
users.add(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeUser(User user){
|
||||||
|
users.remove(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getstartDate() {
|
||||||
|
return startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setstartDate(Date startDate) {
|
||||||
|
this.startDate = startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getendDate() {
|
||||||
|
return endDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setendDate(Date endDate) {
|
||||||
|
this.endDate = endDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<User> getUsers() {
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsers(List<User> users) {
|
||||||
|
this.users = users;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Choice{" +
|
||||||
|
"id=" + id +
|
||||||
|
", startDate=" + startDate +
|
||||||
|
", endDate=" + endDate +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((id == null) ? 0 : id.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
Choice other = (Choice) obj;
|
||||||
|
if (id == null) {
|
||||||
|
if (other.id != null)
|
||||||
|
return false;
|
||||||
|
} else if (!id.equals(other.id))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package fr.istic.tlc.domain;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.GenerationType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.JoinTable;
|
||||||
|
import jakarta.persistence.ManyToMany;
|
||||||
|
import jakarta.persistence.Temporal;
|
||||||
|
import jakarta.persistence.TemporalType;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class Comment {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String content;
|
||||||
|
private String auteur;
|
||||||
|
|
||||||
|
public Comment(){}
|
||||||
|
|
||||||
|
public Comment(String content){
|
||||||
|
this.content=content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(String content) {
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuteur() {
|
||||||
|
return auteur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuteur(String auteur) {
|
||||||
|
this.auteur = auteur;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Comment{" +
|
||||||
|
"id=" + id +
|
||||||
|
", content='" + content + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package fr.istic.tlc.domain;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.GenerationType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class MealPreference {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
User user;
|
||||||
|
|
||||||
|
public MealPreference(){}
|
||||||
|
|
||||||
|
public MealPreference(String content){
|
||||||
|
this.content=content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(String content) {
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUser(User user) {
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "MealPreference{" +
|
||||||
|
"id=" + id +
|
||||||
|
", content='" + content + '\'' +
|
||||||
|
", user=" + user +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
package fr.istic.tlc.domain;
|
||||||
|
|
||||||
|
import fr.istic.tlc.services.Utils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import jakarta.persistence.CascadeType;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.GenerationType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.JoinTable;
|
||||||
|
import jakarta.persistence.ManyToMany;
|
||||||
|
import jakarta.persistence.OneToMany;
|
||||||
|
import jakarta.persistence.OneToOne;
|
||||||
|
import jakarta.persistence.OrderBy;
|
||||||
|
import jakarta.persistence.Temporal;
|
||||||
|
import jakarta.persistence.TemporalType;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
|
import org.hibernate.annotations.UpdateTimestamp;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class Poll {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
private String location;
|
||||||
|
private String description;
|
||||||
|
private boolean has_meal;
|
||||||
|
private String slug = Utils.getInstance().generateSlug(24);
|
||||||
|
private String slugAdmin = Utils.getInstance().generateSlug(24);
|
||||||
|
private String tlkURL = "https://tlk.io/"+Utils.getInstance().generateSlug(12);
|
||||||
|
public boolean clos = false;
|
||||||
|
|
||||||
|
|
||||||
|
@CreationTimestamp
|
||||||
|
private Date createdAt;
|
||||||
|
|
||||||
|
@UpdateTimestamp
|
||||||
|
private Date updatedAt;
|
||||||
|
|
||||||
|
@OneToMany(cascade = CascadeType.ALL)
|
||||||
|
@JoinColumn(name = "pollID")
|
||||||
|
@OrderBy("startDate ASC")
|
||||||
|
List<Choice> pollChoices;
|
||||||
|
|
||||||
|
|
||||||
|
@OneToOne(cascade = {CascadeType.PERSIST,CascadeType.REMOVE,CascadeType.REFRESH})
|
||||||
|
Choice selectedChoice;
|
||||||
|
|
||||||
|
@OneToMany(cascade = {CascadeType.PERSIST,CascadeType.REMOVE,CascadeType.REFRESH})
|
||||||
|
@JoinColumn(name = "pollID")
|
||||||
|
List<Comment> pollComments = new ArrayList<>();
|
||||||
|
|
||||||
|
@OneToMany(cascade = {CascadeType.PERSIST,CascadeType.REMOVE,CascadeType.REFRESH})
|
||||||
|
@JoinColumn(name = "pollID")
|
||||||
|
List<MealPreference> pollMealPreferences = new ArrayList<>();
|
||||||
|
|
||||||
|
private String padURL;
|
||||||
|
|
||||||
|
public Poll(){}
|
||||||
|
|
||||||
|
public Poll(String title, String location, String description, boolean has_meal, List<Choice> pollChoices) {
|
||||||
|
this.title = title;
|
||||||
|
this.location = location;
|
||||||
|
this.description = description;
|
||||||
|
this.has_meal = has_meal;
|
||||||
|
this.pollChoices = pollChoices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addChoice(Choice choice){
|
||||||
|
this.pollChoices.add(choice);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeChoice(Choice choice){
|
||||||
|
this.pollChoices.remove(choice);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addComment(Comment comment){ this.pollComments.add(comment);}
|
||||||
|
|
||||||
|
public void removeComment(Comment comment){ this.pollComments.remove(comment);}
|
||||||
|
|
||||||
|
public void addMealPreference(MealPreference mealPreference){ this.pollMealPreferences.add(mealPreference);}
|
||||||
|
|
||||||
|
public void removeComment(MealPreference mealPreference){ this.pollMealPreferences.remove(mealPreference);}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTlkURL() {
|
||||||
|
return tlkURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTlkURL(String tlkURL) {
|
||||||
|
this.tlkURL = tlkURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Comment> getPollComments() {
|
||||||
|
return pollComments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MealPreference> getPollMealPreferences() {
|
||||||
|
return pollMealPreferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPollMealPreferences(List<MealPreference> pollMealPreferences) {
|
||||||
|
this.pollMealPreferences = pollMealPreferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPollComments(List<Comment> pollComments) {
|
||||||
|
this.pollComments = pollComments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLocation(String location) {
|
||||||
|
this.location = location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHas_meal() {
|
||||||
|
return has_meal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHas_meal(boolean has_meal) {
|
||||||
|
this.has_meal = has_meal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSlug() {
|
||||||
|
return slug;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSlug(String slug) {
|
||||||
|
this.slug = slug;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSlugAdmin() {
|
||||||
|
return slugAdmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSlugAdmin(String slugAdmin) {
|
||||||
|
this.slugAdmin = slugAdmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedAt(Date createdAt) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Choice> getPollChoices() {
|
||||||
|
return pollChoices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPollChoices(List<Choice> pollChoices) {
|
||||||
|
this.pollChoices = pollChoices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Choice getSelectedChoice() {
|
||||||
|
return selectedChoice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSelectedChoice(Choice selectedChoice) {
|
||||||
|
this.selectedChoice = selectedChoice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPadURL() {
|
||||||
|
return this.padURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setPadURL(String padURL) {
|
||||||
|
this.padURL=padURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isClos() {
|
||||||
|
return clos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClos(boolean clos) {
|
||||||
|
this.clos = clos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Poll{" +
|
||||||
|
"id=" + id +
|
||||||
|
", title='" + title + '\'' +
|
||||||
|
", location='" + location + '\'' +
|
||||||
|
", description='" + description + '\'' +
|
||||||
|
", has_meal=" + has_meal +
|
||||||
|
", createdAt=" + createdAt +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getUpdatedAt() {
|
||||||
|
return updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdatedAt(Date updatedAt) {
|
||||||
|
this.updatedAt = updatedAt;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
package fr.istic.tlc.domain;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import jakarta.persistence.CascadeType;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.GenerationType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.ManyToMany;
|
||||||
|
import jakarta.persistence.OneToMany;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class User {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String username;
|
||||||
|
private String mail;
|
||||||
|
private String icsurl;
|
||||||
|
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
@ManyToMany(mappedBy = "users")
|
||||||
|
List<Choice> userChoices = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
@OneToMany(mappedBy="user", cascade = CascadeType.ALL)
|
||||||
|
List<MealPreference> userMealPreferences = new ArrayList<>();
|
||||||
|
|
||||||
|
public User(){}
|
||||||
|
|
||||||
|
public User(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addChoice(Choice choice){
|
||||||
|
this.userChoices.add(choice);
|
||||||
|
}
|
||||||
|
public String getMail() {
|
||||||
|
return mail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMail(String mail) {
|
||||||
|
this.mail = mail;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getIcsurl() {
|
||||||
|
return icsurl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIcsurl(String icsurl) {
|
||||||
|
this.icsurl = icsurl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeChoice(Choice choice){
|
||||||
|
this.userChoices.remove(choice);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void addMealPreference (MealPreference mealPreference) {this.userMealPreferences.add(mealPreference);}
|
||||||
|
|
||||||
|
public void removeMealPreference (MealPreference mealPreference) {this.userMealPreferences.remove(mealPreference);}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Choice> getUserChoices() {
|
||||||
|
return userChoices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MealPreference> getUserMealPreferences() {
|
||||||
|
return userMealPreferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserMealPreferences(List<MealPreference> userMealPreferences) {
|
||||||
|
this.userMealPreferences = userMealPreferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserChoices(List<Choice> userChoices) {
|
||||||
|
this.userChoices = userChoices;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "User{" +
|
||||||
|
"id=" + id +
|
||||||
|
", username='" + username + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package fr.istic.tlc.dto;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ChoiceUser {
|
||||||
|
private List<Long> choices;
|
||||||
|
private String mail;
|
||||||
|
private String pref;
|
||||||
|
private String ics;
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
public List<Long> getChoices() {
|
||||||
|
return choices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChoices(List<Long> value) {
|
||||||
|
this.choices = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMail() {
|
||||||
|
return mail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMail(String value) {
|
||||||
|
this.mail = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPref() {
|
||||||
|
return pref;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPref(String value) {
|
||||||
|
this.pref = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String value) {
|
||||||
|
this.username = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIcs() {
|
||||||
|
return ics;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIcs(String ics) {
|
||||||
|
this.ics = ics;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package fr.istic.tlc.dto;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
|
||||||
|
public class EventDTO {
|
||||||
|
|
||||||
|
private Date startDate;
|
||||||
|
|
||||||
|
private Date endDate;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getStartDate() {
|
||||||
|
return startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStartDate(Date startDate) {
|
||||||
|
this.startDate = startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getEndDate() {
|
||||||
|
return endDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEndDate(Date endDate) {
|
||||||
|
this.endDate = endDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package fr.istic.tlc.dto;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class EventDTOAndSelectedChoice {
|
||||||
|
|
||||||
|
List<EventDTO> eventdtos;
|
||||||
|
List<Long> selectedChoices;
|
||||||
|
public List<EventDTO> getEventdtos() {
|
||||||
|
return eventdtos;
|
||||||
|
}
|
||||||
|
public void setEventdtos(List<EventDTO> eventdtos) {
|
||||||
|
this.eventdtos = eventdtos;
|
||||||
|
}
|
||||||
|
public List<Long> getSelectedChoices() {
|
||||||
|
return selectedChoices;
|
||||||
|
}
|
||||||
|
public void setSelectedChoices(List<Long> selectedChoices) {
|
||||||
|
this.selectedChoices = selectedChoices;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,244 @@
|
|||||||
|
package fr.istic.tlc.resources;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import fr.istic.tlc.dao.ChoiceRepository;
|
||||||
|
import fr.istic.tlc.dao.PollRepository;
|
||||||
|
import fr.istic.tlc.dao.UserRepository;
|
||||||
|
import fr.istic.tlc.domain.Choice;
|
||||||
|
import fr.istic.tlc.domain.Poll;
|
||||||
|
import fr.istic.tlc.domain.User;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api")
|
||||||
|
public class ChoiceResourceEx {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
ChoiceRepository choiceRepository;
|
||||||
|
@Autowired
|
||||||
|
PollRepository pollRepository;
|
||||||
|
@Autowired
|
||||||
|
UserRepository userRepository;
|
||||||
|
|
||||||
|
@GetMapping("/polls/{slug}/choices")
|
||||||
|
public ResponseEntity<List<Choice>> retrieveAllChoicesFromPoll(@PathVariable String slug) {
|
||||||
|
// On vérifie que le choix existe
|
||||||
|
Poll poll = pollRepository.findBySlug(slug);
|
||||||
|
if (poll == null) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
List<Choice> choices = poll.getPollChoices();
|
||||||
|
return new ResponseEntity<>(choices, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/users/{idUser}/choices")
|
||||||
|
public ResponseEntity<List<Choice>> retrieveAllChoicesFromUser(@PathVariable long idUser) {
|
||||||
|
// On vérifie que l'utilisateur existe
|
||||||
|
User user = userRepository.findById(idUser);
|
||||||
|
if (user == null) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
return new ResponseEntity<>(user.getUserChoices(), HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/polls/{slug}/choices/{idChoice}")
|
||||||
|
public ResponseEntity<Choice> retrieveChoiceFromPoll(@PathVariable String slug, @PathVariable long idChoice) {
|
||||||
|
// On vérifie que le choix et le poll existent
|
||||||
|
Poll poll = pollRepository.findBySlug(slug);
|
||||||
|
Choice choice = choiceRepository.findById(idChoice);
|
||||||
|
if (poll == null || choice== null) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
// On vérifie que le choix appartienne bien au poll
|
||||||
|
if(!poll.getPollChoices().contains(choice)){
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
return new ResponseEntity<>(choice, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/users/{idUser}/choices/{idChoice}")
|
||||||
|
public ResponseEntity<Choice> retrieveChoiceFromUser(@PathVariable long idUser, @PathVariable long idChoice) {
|
||||||
|
// On vérifie que le choix et l'utilisateur existent
|
||||||
|
User user = userRepository.findById(idUser);
|
||||||
|
Choice choice = choiceRepository.findById(idChoice);
|
||||||
|
if (user == null || choice == null) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
// On vérifie que le choix appartienne bien à l'utilisateur
|
||||||
|
if(!user.getUserChoices().contains(choice)){
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
return new ResponseEntity<>(choice, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/polls/{slug}/choices")
|
||||||
|
public ResponseEntity<?> deleteChoiceFromPoll(@RequestBody HashMap<String, List<Long>> choices, @PathVariable String slug, @RequestParam String token) {
|
||||||
|
// On vérifie que le poll existe
|
||||||
|
List<Long> idchoices = choices.get("choices");
|
||||||
|
Poll poll = pollRepository.findBySlug(slug);
|
||||||
|
if (poll == null) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
// On vérifie que le token soit bon
|
||||||
|
if(!poll.getSlugAdmin().equals(token)){
|
||||||
|
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
|
||||||
|
}
|
||||||
|
// On enlève les choix du poll
|
||||||
|
for (Long id: idchoices) {
|
||||||
|
// On vérifie que le choice existe
|
||||||
|
Choice choice = choiceRepository.findById(id);
|
||||||
|
if (choice!= null) {
|
||||||
|
// On remove le choice du poll
|
||||||
|
poll.removeChoice(choice);
|
||||||
|
pollRepository.getEntityManager().merge(poll);
|
||||||
|
// On remove le choices des utilisateurs
|
||||||
|
for (User user:userRepository.findAll().list()) {
|
||||||
|
if(user.getUserChoices().contains(choice)){
|
||||||
|
user.getUserChoices().remove(choice);
|
||||||
|
userRepository.getEntityManager().merge(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// On supprime le choice
|
||||||
|
choiceRepository.deleteById(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/polls/{slug}/choices")
|
||||||
|
public ResponseEntity<List<Choice>> createChoices(@RequestBody List<Choice> choices, @PathVariable String slug, @RequestParam String token) {
|
||||||
|
// On vérifie que le poll existe
|
||||||
|
Poll poll = pollRepository.findBySlug(slug);
|
||||||
|
if (poll == null){
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
// On vérifie que le token soit bon
|
||||||
|
if(!poll.getSlugAdmin().equals(token)){
|
||||||
|
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
|
||||||
|
}
|
||||||
|
// On ajoute chaque choix au poll et vice versa
|
||||||
|
for (Choice choice:choices) {
|
||||||
|
this.choiceRepository.persist(choice);
|
||||||
|
poll.addChoice(choice);
|
||||||
|
pollRepository.getEntityManager().merge(poll);
|
||||||
|
}
|
||||||
|
return new ResponseEntity<>(choices, HttpStatus.CREATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/polls/{slug}/choices/{idChoice}")
|
||||||
|
public ResponseEntity<Choice> updateChoice(@Valid @RequestBody Choice choice1, @PathVariable String slug, @PathVariable long idChoice, @RequestParam String token) {
|
||||||
|
// On vérifie que le poll et le choix existent
|
||||||
|
Poll poll = pollRepository.findBySlug(slug);
|
||||||
|
Choice choice = choiceRepository.findById(idChoice);
|
||||||
|
if (poll == null || choice == null) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
// On vérifie que le choix appartienne bien au poll
|
||||||
|
if(!poll.getPollChoices().contains(choice)){
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
// On vérifie que le token soit bon
|
||||||
|
if(!poll.getSlugAdmin().equals(token)){
|
||||||
|
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
|
||||||
|
}
|
||||||
|
// On met à jour l'ancien choix
|
||||||
|
Choice ancientChoice = choice;
|
||||||
|
if (choice1.getstartDate()!=null){
|
||||||
|
ancientChoice.setstartDate(choice1.getstartDate());
|
||||||
|
}
|
||||||
|
if (choice1.getendDate()!=null){
|
||||||
|
ancientChoice.setendDate(choice1.getendDate());
|
||||||
|
}
|
||||||
|
// On update la bdd
|
||||||
|
Choice updatedChoice = choiceRepository.getEntityManager().merge(ancientChoice);
|
||||||
|
return new ResponseEntity<>(updatedChoice, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/polls/{slug}/vote/{idUser}")
|
||||||
|
public ResponseEntity<Object> vote(@RequestBody HashMap<String, List<Long>> choices, @PathVariable String slug, @PathVariable long idUser) {
|
||||||
|
// On vérifie que le poll et l'utilisateur existent
|
||||||
|
List<Long> idchoices = choices.get("choices");
|
||||||
|
Poll poll = pollRepository.findBySlug(slug);
|
||||||
|
User user = userRepository.findById(idUser);
|
||||||
|
if (poll == null || user == null){
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
for (Long choice : idchoices) {
|
||||||
|
// On vérifie que le choice existe
|
||||||
|
Choice optchoice = choiceRepository.findById(choice);
|
||||||
|
if (optchoice == null){
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
// On vérifie que le choix appartienne bien au poll
|
||||||
|
if(!poll.getPollChoices().contains(optchoice)){
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
// On vérifie que le user n'ai pas déjà voté pour ce choix
|
||||||
|
if(user.getUserChoices().contains(optchoice)){
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
// On ajoute le choix à la liste de l'utilisateur et vice versa
|
||||||
|
optchoice.addUser(user);
|
||||||
|
choiceRepository.getEntityManager().merge(optchoice);
|
||||||
|
}
|
||||||
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/polls/{slug}/choices/{idChoice}/removevote/{idUser}")
|
||||||
|
public ResponseEntity<Object> removeVote(@PathVariable String slug, @PathVariable long idChoice, @PathVariable long idUser) {
|
||||||
|
// On vérifie que le poll, le choix et l'utilisateur existent
|
||||||
|
Poll poll = pollRepository.findBySlug(slug);
|
||||||
|
Choice choice = choiceRepository.findById(idChoice);
|
||||||
|
User user = userRepository.findById(idUser);
|
||||||
|
if (poll == null || choice == null || user == null){
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
// On vérifie que le choix appartienne bien au poll
|
||||||
|
if(!poll.getPollChoices().contains(choice)){
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
// On vérifie que le user ait bien voté pour ce choix
|
||||||
|
if(!user.getUserChoices().contains(choice)){
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
// On retire le choix à la liste de l'utilisateur et vice versa
|
||||||
|
choice.removeUser(user);
|
||||||
|
choiceRepository.getEntityManager().merge(choice);
|
||||||
|
user.removeChoice(choice);
|
||||||
|
userRepository.getEntityManager().merge(user);
|
||||||
|
|
||||||
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/polls/{slug}/choices/{idChoice}/count")
|
||||||
|
public ResponseEntity<Object> numberOfVoteForChoice(@PathVariable String slug, @PathVariable long idChoice){
|
||||||
|
// On vérifie que le poll et choix existent
|
||||||
|
Poll poll = pollRepository.findBySlug(slug);
|
||||||
|
Choice choice = choiceRepository.findById(idChoice);
|
||||||
|
if (poll == null || choice == null){
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
// On vérifie que le choix appartienne bien au poll
|
||||||
|
if(!poll.getPollChoices().contains(choice)){
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
// On compte le nombre de vote pour le choix
|
||||||
|
return new ResponseEntity<>(choice.getUsers().size(),HttpStatus.OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package fr.istic.tlc.resources;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import fr.istic.tlc.dao.CommentRepository;
|
||||||
|
import fr.istic.tlc.dao.PollRepository;
|
||||||
|
import fr.istic.tlc.domain.Comment;
|
||||||
|
import fr.istic.tlc.domain.Poll;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api")
|
||||||
|
public class CommentResourceEx {
|
||||||
|
@Autowired
|
||||||
|
PollRepository pollRepository;
|
||||||
|
@Autowired
|
||||||
|
CommentRepository commentRepository;
|
||||||
|
|
||||||
|
/* @GetMapping("users/{idUser}/comments")
|
||||||
|
public ResponseEntity<List<Comment>> getAllCommentsFromUser(@PathVariable long idUser) {
|
||||||
|
// On vérifie que l'utilisateur existe
|
||||||
|
User optUser = userRepository.findById(idUser);
|
||||||
|
if(optUser== null){
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
return new ResponseEntity<>(optUser.getUserComments(), HttpStatus.OK);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
@GetMapping("polls/{slug}/comments")
|
||||||
|
public ResponseEntity<Object> getAllCommentsFromPoll(@PathVariable String slug) {
|
||||||
|
// On vérifie que le poll existe
|
||||||
|
Poll optPoll = pollRepository.findBySlug(slug);
|
||||||
|
if(optPoll== null){
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
return new ResponseEntity<>(optPoll.getPollComments(),HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("polls/{slug}/comments/{idComment}")
|
||||||
|
public ResponseEntity<Object> getCommentFromPoll(@PathVariable String slug, @PathVariable long idComment){
|
||||||
|
// On vérifie que le poll et le comment existe
|
||||||
|
Poll optPoll = pollRepository.findBySlug(slug);
|
||||||
|
Comment optComment = commentRepository.findById(idComment);
|
||||||
|
if(optPoll== null || optComment== null){
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
// On vérifie que le comment appartienne bien au poll
|
||||||
|
if (!optPoll.getPollComments().contains(optComment)){
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
return new ResponseEntity<>(optComment,HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @PostMapping("polls/{slug}/comments/{idUser}")
|
||||||
|
public ResponseEntity<Object> createComment(@Valid @RequestBody Comment comment, @PathVariable String slug, @PathVariable long idUser){
|
||||||
|
// On vérifie que le poll et le User existe
|
||||||
|
Poll poll = pollRepository.findBySlug(slug);
|
||||||
|
User user = userRepository.findById(idUser);
|
||||||
|
if (poll== null || user== null){
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
// On set le user dans comment
|
||||||
|
comment.setUser(user);
|
||||||
|
// On ajoute le commentaire dans le poll
|
||||||
|
poll.addComment(comment);
|
||||||
|
pollRepository.save(poll);
|
||||||
|
// On save le commentaire
|
||||||
|
Comment savedComment = commentRepository.save(comment);
|
||||||
|
return new ResponseEntity<>(savedComment, HttpStatus.CREATED);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
package fr.istic.tlc.resources;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
|
import javax.mail.MessagingException;
|
||||||
|
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.Path;
|
||||||
|
import jakarta.ws.rs.PathParam;
|
||||||
|
import jakarta.ws.rs.Produces;
|
||||||
|
import jakarta.ws.rs.core.MediaType;
|
||||||
|
import jakarta.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
|
||||||
|
import org.apache.http.impl.nio.client.HttpAsyncClients;
|
||||||
|
|
||||||
|
import fr.istic.tlc.dao.ChoiceRepository;
|
||||||
|
import fr.istic.tlc.dao.PollRepository;
|
||||||
|
import fr.istic.tlc.dao.UserRepository;
|
||||||
|
import fr.istic.tlc.domain.Choice;
|
||||||
|
import fr.istic.tlc.domain.Poll;
|
||||||
|
import fr.istic.tlc.dto.EventDTO;
|
||||||
|
import fr.istic.tlc.dto.EventDTOAndSelectedChoice;
|
||||||
|
import fr.istic.tlc.services.Utils;
|
||||||
|
import net.fortuna.ical4j.data.CalendarBuilder;
|
||||||
|
import net.fortuna.ical4j.data.ParserException;
|
||||||
|
import net.fortuna.ical4j.model.Calendar;
|
||||||
|
import net.fortuna.ical4j.model.Component;
|
||||||
|
import net.fortuna.ical4j.model.ComponentList;
|
||||||
|
import net.fortuna.ical4j.model.DateTime;
|
||||||
|
import net.fortuna.ical4j.model.Period;
|
||||||
|
import net.fortuna.ical4j.model.PeriodList;
|
||||||
|
import net.fortuna.ical4j.model.component.CalendarComponent;
|
||||||
|
import net.fortuna.ical4j.model.component.VEvent;
|
||||||
|
import net.fortuna.ical4j.util.MapTimeZoneCache;
|
||||||
|
|
||||||
|
@Path("/api/ics")
|
||||||
|
public class ICSResources {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
PollRepository pollRep;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
UserRepository userRep;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ChoiceRepository choiceRep;
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("polls/{slug}/{ics}")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public EventDTOAndSelectedChoice parseCalendartoAppointments(@PathParam("slug") String slug,
|
||||||
|
@PathParam("ics") String ics)
|
||||||
|
throws IOException, ParserException, InterruptedException, ExecutionException, MessagingException {
|
||||||
|
EventDTOAndSelectedChoice result = new EventDTOAndSelectedChoice();
|
||||||
|
List<EventDTO> appointments = new ArrayList<>();
|
||||||
|
List<Long> selectedChoices = new ArrayList<>();
|
||||||
|
result.setEventdtos(appointments);
|
||||||
|
result.setSelectedChoices(selectedChoices);
|
||||||
|
|
||||||
|
// Get Poll
|
||||||
|
Poll p = this.pollRep.findBySlug(slug);
|
||||||
|
Date minDate = new Date();
|
||||||
|
if (p != null) {
|
||||||
|
// Get minimal date for Poll to filter ics
|
||||||
|
|
||||||
|
if (p.getPollChoices().size() > 0 && minDate.after(p.getPollChoices().get(0).getstartDate()))
|
||||||
|
minDate = p.getPollChoices().get(0).getstartDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get user to get its ICS
|
||||||
|
// User u = this.userRep.find("mail", usermail).firstResult();
|
||||||
|
byte[] decodedBytes = Base64.getDecoder().decode(ics);
|
||||||
|
String decodedString = new String(decodedBytes);
|
||||||
|
|
||||||
|
if (decodedString != null && !"".equals(decodedString)) {
|
||||||
|
// String s =
|
||||||
|
// "http://zimbra.inria.fr/home/olivier.barais@irisa.fr/Calendar.ics";
|
||||||
|
|
||||||
|
// Query the ics url
|
||||||
|
|
||||||
|
System.setProperty("net.fortuna.ical4j.timezone.cache.impl", MapTimeZoneCache.class.getName());
|
||||||
|
CloseableHttpAsyncClient client = HttpAsyncClients.createDefault();
|
||||||
|
client.start();
|
||||||
|
HttpGet request = new HttpGet(decodedString);
|
||||||
|
|
||||||
|
Future<HttpResponse> future = client.execute(request, null);
|
||||||
|
HttpResponse response = future.get();
|
||||||
|
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
response.getEntity().writeTo(out);
|
||||||
|
String responseString = out.toString();
|
||||||
|
out.close();
|
||||||
|
client.close();
|
||||||
|
|
||||||
|
// Parse result
|
||||||
|
StringReader sin = new StringReader(responseString);
|
||||||
|
CalendarBuilder builder = new CalendarBuilder();
|
||||||
|
Calendar calendar = builder.build(sin);
|
||||||
|
ComponentList<CalendarComponent> events = calendar.getComponents(Component.VEVENT);
|
||||||
|
List<Choice> choices = new ArrayList<Choice>();
|
||||||
|
if (p!= null)
|
||||||
|
choices = p.getPollChoices();
|
||||||
|
// Create Event to draw
|
||||||
|
java.util.Calendar calEnd = java.util.Calendar.getInstance();
|
||||||
|
calEnd.setTime(new Date());
|
||||||
|
calEnd.add(java.util.Calendar.YEAR, 1);
|
||||||
|
DateTime start = new DateTime(minDate);
|
||||||
|
DateTime end = new DateTime(calEnd.getTime());
|
||||||
|
for (CalendarComponent event : events) {
|
||||||
|
|
||||||
|
Period period = new Period(start, end);
|
||||||
|
PeriodList list = event.calculateRecurrenceSet(period);
|
||||||
|
for (Period p1 : list) {
|
||||||
|
if (minDate.before(p1.getStart())) {
|
||||||
|
EventDTO a = new EventDTO();
|
||||||
|
a.setStartDate(p1.getStart());
|
||||||
|
a.setEndDate(p1.getEnd());
|
||||||
|
if (((VEvent) event).getSummary() != null)
|
||||||
|
a.setDescription(((VEvent) event).getSummary().getValue());
|
||||||
|
|
||||||
|
// Si intersection ajoute l'ID du choice comme ID selected
|
||||||
|
// https://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap
|
||||||
|
for (Choice choice : choices) {
|
||||||
|
if (Utils.getInstance().intersect(choice.getstartDate(), choice.getendDate(), p1.getStart(),
|
||||||
|
p1.getEnd())) {
|
||||||
|
if (!selectedChoices.contains(choice.getId())) {
|
||||||
|
selectedChoices.add(choice.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
appointments.add(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package fr.istic.tlc.resources;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import fr.istic.tlc.dao.ChoiceRepository;
|
||||||
|
import fr.istic.tlc.dao.MealPreferenceRepository;
|
||||||
|
import fr.istic.tlc.dao.PollRepository;
|
||||||
|
import fr.istic.tlc.dao.UserRepository;
|
||||||
|
import fr.istic.tlc.domain.MealPreference;
|
||||||
|
import fr.istic.tlc.domain.Poll;
|
||||||
|
import fr.istic.tlc.domain.User;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api")
|
||||||
|
public class MealPreferenceResource {
|
||||||
|
@Autowired
|
||||||
|
ChoiceRepository choiceRepository;
|
||||||
|
@Autowired
|
||||||
|
PollRepository pollRepository;
|
||||||
|
@Autowired
|
||||||
|
UserRepository userRepository;
|
||||||
|
@Autowired
|
||||||
|
MealPreferenceRepository mealPreferenceRepository;
|
||||||
|
|
||||||
|
@GetMapping("polls/{slug}/mealpreferences")
|
||||||
|
public ResponseEntity<Object> getAllMealPreferencesFromPoll(@PathVariable String slug) {
|
||||||
|
// On vérifie que le poll existe
|
||||||
|
Poll optPoll = pollRepository.findBySlug(slug);
|
||||||
|
if(optPoll == null){
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
return new ResponseEntity<>(optPoll.getPollMealPreferences(),HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("polls/{slug}/mealpreference/{idMealPreference}")
|
||||||
|
public ResponseEntity<Object> getMealPreferenceFromPoll(@PathVariable String slug, @PathVariable long idMealPreference){
|
||||||
|
// On vérifie que le poll et la meal preference existe
|
||||||
|
Poll optPoll = pollRepository.findBySlug(slug);
|
||||||
|
MealPreference optMealPreference = mealPreferenceRepository.findById(idMealPreference);
|
||||||
|
if(optPoll == null || optMealPreference == null){
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
// On vérifie que la meal preference appartienne bien au poll
|
||||||
|
if (!optPoll.getPollMealPreferences().contains(optMealPreference)){
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
return new ResponseEntity<>(optMealPreference,HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("polls/{slug}/mealpreference/{idUser}")
|
||||||
|
public ResponseEntity<Object> createMealPreference(@Valid @RequestBody MealPreference mealPreference, @PathVariable String slug, @PathVariable long idUser){
|
||||||
|
// On vérifie que le poll et le User existe
|
||||||
|
Poll poll = pollRepository.findBySlug(slug);
|
||||||
|
User user = userRepository.findById(idUser);
|
||||||
|
if (poll == null || user == null){
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
// On set le user dans la meal preference
|
||||||
|
mealPreference.setUser(user);
|
||||||
|
// On ajoute la meal preference dans le poll
|
||||||
|
poll.addMealPreference(mealPreference);
|
||||||
|
// On save la meal preference
|
||||||
|
mealPreferenceRepository.persist(mealPreference);
|
||||||
|
pollRepository.getEntityManager().merge(poll);
|
||||||
|
return new ResponseEntity<>(mealPreference, HttpStatus.CREATED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
package fr.istic.tlc.resources;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.transaction.Transactional;
|
||||||
|
import jakarta.ws.rs.Consumes;
|
||||||
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.POST;
|
||||||
|
import jakarta.ws.rs.PUT;
|
||||||
|
import jakarta.ws.rs.Path;
|
||||||
|
import jakarta.ws.rs.PathParam;
|
||||||
|
import jakarta.ws.rs.Produces;
|
||||||
|
import jakarta.ws.rs.core.MediaType;
|
||||||
|
import jakarta.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import fr.istic.tlc.dao.ChoiceRepository;
|
||||||
|
import fr.istic.tlc.dao.CommentRepository;
|
||||||
|
import fr.istic.tlc.dao.MealPreferenceRepository;
|
||||||
|
import fr.istic.tlc.dao.PollRepository;
|
||||||
|
import fr.istic.tlc.dao.UserRepository;
|
||||||
|
import fr.istic.tlc.domain.Choice;
|
||||||
|
import fr.istic.tlc.domain.Comment;
|
||||||
|
import fr.istic.tlc.domain.MealPreference;
|
||||||
|
import fr.istic.tlc.domain.Poll;
|
||||||
|
import fr.istic.tlc.domain.User;
|
||||||
|
import fr.istic.tlc.dto.ChoiceUser;
|
||||||
|
import fr.istic.tlc.services.SendEmail;
|
||||||
|
|
||||||
|
@Path("/api/poll")
|
||||||
|
public class NewPollResourceEx {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
PollRepository pollRep;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
UserRepository userRep;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ChoiceRepository choiceRep;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MealPreferenceRepository mealprefRep;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
CommentRepository commentRep;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
SendEmail sendmail;
|
||||||
|
|
||||||
|
@Path("/slug/{slug}")
|
||||||
|
@GET
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public Poll getPollBySlug(@PathParam("slug") String slug) {
|
||||||
|
Poll p = pollRep.findBySlug(slug);
|
||||||
|
if (p != null)
|
||||||
|
p.getPollComments().clear();
|
||||||
|
p.setSlugAdmin("");
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("/aslug/{aslug}")
|
||||||
|
@GET
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public Poll getPollByASlug(@PathParam("aslug") String aslug) {
|
||||||
|
return pollRep.findByAdminSlug(aslug);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("/comment/{slug}")
|
||||||
|
@POST
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@Transactional
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public Comment createComment4Poll(@PathParam("slug") String slug, Comment c) {
|
||||||
|
this.commentRep.persist(c);
|
||||||
|
Poll p = pollRep.findBySlug(slug);
|
||||||
|
p.addComment(c);
|
||||||
|
this.pollRep.persistAndFlush(p);
|
||||||
|
return c;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("/update1")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@Transactional
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public Poll updatePoll(Poll p) {
|
||||||
|
System.err.println( "p " + p);
|
||||||
|
Poll p1 = pollRep.findById(p.getId());
|
||||||
|
List<Choice> choicesToRemove = new ArrayList<Choice>();
|
||||||
|
for (Choice c : p1.getPollChoices()) {
|
||||||
|
if (!p.getPollChoices().contains(c)) {
|
||||||
|
|
||||||
|
choicesToRemove.add(c);
|
||||||
|
System.err.println("toremove " + c.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
for (Choice c : p.getPollChoices()) {
|
||||||
|
if (c.getId() != null) {
|
||||||
|
this.choiceRep.getEntityManager().merge(c);
|
||||||
|
} else {
|
||||||
|
this.choiceRep.getEntityManager().persist(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
for (Choice c : choicesToRemove) {
|
||||||
|
if (c.equals(p1.getSelectedChoice())) {
|
||||||
|
p.setSelectedChoice(null);
|
||||||
|
p1.setSelectedChoice(null);
|
||||||
|
p.setClos(false);
|
||||||
|
}
|
||||||
|
for (User u : c.getUsers()) {
|
||||||
|
u.getUserChoices().remove(c);
|
||||||
|
}
|
||||||
|
c.getUsers().clear();
|
||||||
|
this.choiceRep.delete(c);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Choice c : p.getPollChoices()) {
|
||||||
|
System.err.println("tomerge " + c.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
Poll p2 = this.pollRep.getEntityManager().merge(p);
|
||||||
|
return p2;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("/choiceuser")
|
||||||
|
@POST
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@Transactional
|
||||||
|
public User addChoiceUser(ChoiceUser userChoice) {
|
||||||
|
User u = this.userRep.find("mail", userChoice.getMail()).firstResult();
|
||||||
|
if (u == null) {
|
||||||
|
u = new User();
|
||||||
|
u.setUsername(userChoice.getUsername());
|
||||||
|
u.setIcsurl(userChoice.getIcs());
|
||||||
|
u.setMail(userChoice.getMail());
|
||||||
|
this.userRep.persist(u);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (userChoice.getPref() != null && !"".equals(userChoice.getPref())) {
|
||||||
|
MealPreference mp = new MealPreference();
|
||||||
|
mp.setContent(userChoice.getPref());
|
||||||
|
mp.setUser(u);
|
||||||
|
this.mealprefRep.persist(mp);
|
||||||
|
}
|
||||||
|
for (Long choiceId : userChoice.getChoices()) {
|
||||||
|
Choice c = this.choiceRep.findById(choiceId);
|
||||||
|
c.addUser(u);
|
||||||
|
this.choiceRep.persistAndFlush(c);
|
||||||
|
}
|
||||||
|
return u;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("/selectedchoice/{choiceid}")
|
||||||
|
@POST
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@Transactional
|
||||||
|
public void closePoll(@PathParam("choiceid") String choiceid) {
|
||||||
|
Choice c = choiceRep.findById(Long.parseLong(choiceid));
|
||||||
|
Poll p = this.pollRep.find("select p from Poll as p join p.pollChoices as c where c.id= ?1", c.getId())
|
||||||
|
.firstResult();
|
||||||
|
p.setClos(true);
|
||||||
|
p.setSelectedChoice(c);
|
||||||
|
this.pollRep.persist(p);
|
||||||
|
this.sendmail.sendASimpleEmail(p);
|
||||||
|
// TODO Send Email
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET()
|
||||||
|
@Path("polls/{slug}/comments")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public List<Comment> getAllCommentsFromPoll(@PathParam("slug") String slug) {
|
||||||
|
Poll p = this.pollRep.findBySlug(slug);
|
||||||
|
if (p!= null)
|
||||||
|
return p.getPollComments();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
package fr.istic.tlc.resources;
|
||||||
|
|
||||||
|
import fr.istic.tlc.services.Utils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import jakarta.transaction.Transactional;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
|
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import fr.istic.tlc.dao.PollRepository;
|
||||||
|
import fr.istic.tlc.domain.Poll;
|
||||||
|
import io.quarkus.panache.common.Sort;
|
||||||
|
import net.gjerull.etherpad.client.EPLiteClient;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api")
|
||||||
|
public class PollResourceEx {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
PollRepository pollRepository;
|
||||||
|
|
||||||
|
@ConfigProperty(name = "doodle.usepad")
|
||||||
|
Boolean usePad = true;
|
||||||
|
@ConfigProperty(name = "doodle.internalPadUrl", defaultValue="http://etherpad:9001/")
|
||||||
|
String padUrl = "";
|
||||||
|
@ConfigProperty(name = "doodle.externalPadUrl", defaultValue="http://etherpad.diverse-team.fr/")
|
||||||
|
String externalPadUrl = "";
|
||||||
|
@ConfigProperty(name = "doodle.padApiKey")
|
||||||
|
String apikey = "";
|
||||||
|
EPLiteClient client;
|
||||||
|
|
||||||
|
@GetMapping("/polls")
|
||||||
|
public ResponseEntity<List<Poll>> retrieveAllpolls() {
|
||||||
|
// On récupère la liste de tous les poll qu'on trie ensuite par titre
|
||||||
|
List<Poll> polls = pollRepository.findAll(Sort.by("title", Sort.Direction.Ascending)).list();
|
||||||
|
return new ResponseEntity<>(polls, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/polls/{slug}")
|
||||||
|
public ResponseEntity<Poll> retrievePoll(@PathVariable String slug, @RequestParam(required = false) String token) {
|
||||||
|
// On vérifie que le poll existe
|
||||||
|
Poll poll = pollRepository.findBySlug(slug);
|
||||||
|
if (poll == null) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
// Si un token est donné, on vérifie qu'il soit bon
|
||||||
|
if (token != null && !poll.getSlugAdmin().equals(token)) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
|
||||||
|
}
|
||||||
|
poll.setSlugAdmin("");
|
||||||
|
return new ResponseEntity<>(poll, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/polls/{slug}/pad")
|
||||||
|
public ResponseEntity<String> retrievePadURL(@PathVariable("slug") String slug) {
|
||||||
|
// On vérifie que le poll existe
|
||||||
|
Poll poll = pollRepository.findBySlug(slug);
|
||||||
|
if (poll == null) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
return new ResponseEntity<>(poll.getPadURL(), HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/polls/{slug}")
|
||||||
|
@Transactional
|
||||||
|
public ResponseEntity<Poll> deletePoll(@PathVariable("slug") String slug, @RequestParam String token) {
|
||||||
|
// On vérifie que le poll existe
|
||||||
|
Poll poll = pollRepository.findBySlug(slug);
|
||||||
|
if (poll == null) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
// On vérifie que le token soit bon
|
||||||
|
if (!poll.getSlugAdmin().equals(token)) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
|
||||||
|
}
|
||||||
|
// On supprime tous les choix du poll
|
||||||
|
// Fait automatiquement par le cascade type ALL
|
||||||
|
|
||||||
|
// On supprime tous les commentaires du poll
|
||||||
|
// Fait automatiquement par le cascade type ALL
|
||||||
|
|
||||||
|
// On supprime le pad
|
||||||
|
if (client == null) {
|
||||||
|
client = new EPLiteClient(padUrl, apikey);
|
||||||
|
}
|
||||||
|
|
||||||
|
client.deletePad(getPadId(poll));
|
||||||
|
// On supprime le poll de la bdd
|
||||||
|
pollRepository.deleteById(poll.getId());
|
||||||
|
return new ResponseEntity<>(poll, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("/polls")
|
||||||
|
@Transactional
|
||||||
|
public ResponseEntity<Poll> createPoll(@Valid @RequestBody Poll poll) {
|
||||||
|
// On enregistre le poll dans la bdd
|
||||||
|
String padId = Utils.getInstance().generateSlug(15);
|
||||||
|
if (this.usePad) {
|
||||||
|
if (client == null) {
|
||||||
|
client = new EPLiteClient(padUrl, apikey);
|
||||||
|
}
|
||||||
|
client.createPad(padId);
|
||||||
|
initPad(poll.getTitle(), poll.getLocation(), poll.getDescription(), client, padId);
|
||||||
|
poll.setPadURL(externalPadUrl + "p/" + padId);
|
||||||
|
}
|
||||||
|
pollRepository.persist(poll);
|
||||||
|
return new ResponseEntity<>(poll, HttpStatus.CREATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/polls/{slug}")
|
||||||
|
@Transactional
|
||||||
|
public ResponseEntity<Object> updatePoll(@Valid @RequestBody Poll poll, @PathVariable String slug,
|
||||||
|
@RequestParam String token) {
|
||||||
|
// On vérifie que le poll existe
|
||||||
|
Poll optionalPoll = pollRepository.findBySlug(slug);
|
||||||
|
if (optionalPoll == null)
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
// On vérifie que le token soit bon
|
||||||
|
if (!optionalPoll.getSlugAdmin().equals(token)) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
|
||||||
|
}
|
||||||
|
// On met au poll le bon id et les bons slugs
|
||||||
|
Poll ancientPoll = optionalPoll;
|
||||||
|
// On se connecte au pad
|
||||||
|
String padId = getPadId(ancientPoll);
|
||||||
|
|
||||||
|
// On sauvegarde les anciennes données pour mettre à jour le pad
|
||||||
|
String title = ancientPoll.getTitle();
|
||||||
|
String location = ancientPoll.getLocation();
|
||||||
|
String description = ancientPoll.getDescription();
|
||||||
|
|
||||||
|
// On met à jour l'ancien poll
|
||||||
|
if (poll.getTitle() != null) {
|
||||||
|
ancientPoll.setTitle(poll.getTitle());
|
||||||
|
}
|
||||||
|
if (poll.getLocation() != null) {
|
||||||
|
ancientPoll.setLocation(poll.getLocation());
|
||||||
|
}
|
||||||
|
if (poll.getDescription() != null) {
|
||||||
|
ancientPoll.setDescription(poll.getDescription());
|
||||||
|
}
|
||||||
|
ancientPoll.setHas_meal(poll.isHas_meal());
|
||||||
|
// On update le pad
|
||||||
|
String ancientPad = (String) client.getText(padId).get("text");
|
||||||
|
ancientPad = ancientPad.replaceFirst(title, ancientPoll.getTitle());
|
||||||
|
ancientPad = ancientPad.replaceFirst(location, ancientPoll.getLocation());
|
||||||
|
ancientPad = ancientPad.replaceFirst(description, ancientPoll.getDescription());
|
||||||
|
client.setText(padId, ancientPad);
|
||||||
|
// On enregistre le poll dans la bdd
|
||||||
|
Poll updatedPoll = pollRepository.getEntityManager().merge(ancientPoll);
|
||||||
|
return new ResponseEntity<>(updatedPoll, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void initPad(String pollTitle, String pollLocation, String pollDescription, EPLiteClient client,
|
||||||
|
String padId) {
|
||||||
|
final String str = pollTitle + '\n' + "Localisation : " + pollLocation + '\n' + "Description : "
|
||||||
|
+ pollDescription + '\n';
|
||||||
|
client.setText(padId, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getPadId(Poll poll) {
|
||||||
|
//return poll.getPadURL().substring(poll.getPadURL().length() - 6);
|
||||||
|
return poll.getPadURL().substring(poll.getPadURL().lastIndexOf('/') + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
package fr.istic.tlc.resources;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import fr.istic.tlc.dao.ChoiceRepository;
|
||||||
|
import fr.istic.tlc.dao.PollRepository;
|
||||||
|
import fr.istic.tlc.dao.UserRepository;
|
||||||
|
import fr.istic.tlc.domain.Choice;
|
||||||
|
import fr.istic.tlc.domain.Poll;
|
||||||
|
import fr.istic.tlc.domain.User;
|
||||||
|
import io.quarkus.panache.common.Sort;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api")
|
||||||
|
public class UserResource {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
ChoiceRepository choiceRepository;
|
||||||
|
@Autowired
|
||||||
|
PollRepository pollRepository;
|
||||||
|
@Autowired
|
||||||
|
UserRepository userRepository;
|
||||||
|
|
||||||
|
@GetMapping("/users")
|
||||||
|
public ResponseEntity<List<User>> retrieveAllUsers() {
|
||||||
|
// On récupère tous les utilisateurs qu'on trie ensuite par username
|
||||||
|
List<User> users = userRepository.findAll(Sort.by( "username", Sort.Direction.Ascending)).list();
|
||||||
|
return new ResponseEntity<>(users, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/users/{idUser}")
|
||||||
|
public ResponseEntity<User> retrieveUser(@PathVariable long idUser) {
|
||||||
|
// On vérifie que l'utilisateur existe
|
||||||
|
User user = userRepository.findById(idUser);
|
||||||
|
if (user== null) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
return new ResponseEntity<>(user, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/polls/{slug}/users")
|
||||||
|
public ResponseEntity<List<User>> getAllUserFromPoll(@PathVariable String slug) {
|
||||||
|
List<User> users = new ArrayList<>();
|
||||||
|
// On vérifie que le poll existe
|
||||||
|
Poll poll = pollRepository.findBySlug(slug);
|
||||||
|
if (poll== null) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
// On parcours les choix du poll pour récupérer les users ayant voté
|
||||||
|
if (!poll.getPollChoices().isEmpty()) {
|
||||||
|
for (Choice choice : poll.getPollChoices()) {
|
||||||
|
if (!choice.getUsers().isEmpty()) {
|
||||||
|
for (User user : choice.getUsers()) {
|
||||||
|
// On vérifie que le user ne soit pas déjà dans la liste
|
||||||
|
if (!users.contains(user)) {
|
||||||
|
users.add(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ResponseEntity<>(users, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/users/{idUser}")
|
||||||
|
public ResponseEntity<User> deleteUser(@PathVariable long idUser) {
|
||||||
|
// On vérifie que l'utilisateur existe
|
||||||
|
User user = userRepository.findById(idUser);
|
||||||
|
if (user== null) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
// On supprime l'utilisateur de la liste d'utilisateur de chaque choix
|
||||||
|
for (Choice choice : user.getUserChoices()) {
|
||||||
|
choice.removeUser(user);
|
||||||
|
choiceRepository.getEntityManager().merge(choice);
|
||||||
|
}
|
||||||
|
// On supprime les commentaires de l'utilisateurs
|
||||||
|
// Fait automatiquement par le cascade type ALL
|
||||||
|
|
||||||
|
// On supprime l'utilisateur de la bdd
|
||||||
|
userRepository.deleteById(idUser);
|
||||||
|
return new ResponseEntity<>(user, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/users")
|
||||||
|
public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
|
||||||
|
// On sauvegarde l'utilisateur dans la bdd
|
||||||
|
userRepository.persist(user);
|
||||||
|
return new ResponseEntity<>(user, HttpStatus.CREATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/users/{idUser}")
|
||||||
|
public ResponseEntity<User> updateUser(@PathVariable long idUser, @Valid @RequestBody User user) {
|
||||||
|
// On vérifie que l'utilisateur existe
|
||||||
|
User optionalUser = userRepository.findById(idUser);
|
||||||
|
if (optionalUser== null) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
// On met le bon id sur l'utilisateur
|
||||||
|
User ancientUser = optionalUser;
|
||||||
|
if (user.getUsername() != null) {
|
||||||
|
ancientUser.setUsername(user.getUsername());
|
||||||
|
}
|
||||||
|
// On update l'utilisateur dans la bdd
|
||||||
|
User updatedUser = userRepository.getEntityManager().merge(ancientUser);
|
||||||
|
return new ResponseEntity<>(updatedUser, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,332 @@
|
|||||||
|
package fr.istic.tlc.resources.features;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
||||||
|
|
||||||
|
import fr.istic.tlc.dao.ChoiceRepository;
|
||||||
|
import fr.istic.tlc.dao.PollRepository;
|
||||||
|
import fr.istic.tlc.dao.UserRepository;
|
||||||
|
import fr.istic.tlc.domain.Choice;
|
||||||
|
import fr.istic.tlc.domain.Poll;
|
||||||
|
import fr.istic.tlc.domain.User;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.Path;
|
||||||
|
import jakarta.ws.rs.PathParam;
|
||||||
|
import jakarta.ws.rs.Produces;
|
||||||
|
import jakarta.ws.rs.core.MediaType;
|
||||||
|
import jakarta.ws.rs.core.Response;
|
||||||
|
import jxl.Workbook;
|
||||||
|
import jxl.format.Alignment;
|
||||||
|
import jxl.format.Border;
|
||||||
|
import jxl.format.BorderLineStyle;
|
||||||
|
import jxl.format.Colour;
|
||||||
|
import jxl.format.VerticalAlignment;
|
||||||
|
import jxl.write.Label;
|
||||||
|
import jxl.write.Number;
|
||||||
|
import jxl.write.WritableCellFormat;
|
||||||
|
import jxl.write.WritableFont;
|
||||||
|
import jxl.write.WritableSheet;
|
||||||
|
import jxl.write.WritableWorkbook;
|
||||||
|
|
||||||
|
@Path("/api")
|
||||||
|
public class ExportResource {
|
||||||
|
@Inject
|
||||||
|
ChoiceRepository choiceRepository;
|
||||||
|
@Inject
|
||||||
|
PollRepository pollRepository;
|
||||||
|
@Inject
|
||||||
|
UserRepository userRepository;
|
||||||
|
|
||||||
|
|
||||||
|
@ConfigProperty(name = "doodle.tmpfolder")
|
||||||
|
String EXCEL_FILE_LOCATION = "/tmp/excelFiles";
|
||||||
|
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Produces(MediaType.APPLICATION_OCTET_STREAM)
|
||||||
|
@Path("/polls/{slug}/results")
|
||||||
|
public Response downloadResultsExcel(@PathParam("slug") String slug) throws IOException {
|
||||||
|
Poll poll = pollRepository.findBySlug(slug);
|
||||||
|
if (poll == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String filePath = createExcelFile(poll, slug);
|
||||||
|
return getHttpEntityToDownload(filePath, "vnd.ms-excel");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @RequestMapping(value = "/polls/{slug}/print", method = RequestMethod.GET,
|
||||||
|
* produces = APPLICATION_PDF) public @ResponseBody HttpEntity<byte[]>
|
||||||
|
* downloadResultsPdf(@PathVariable String slug) throws IOException { Poll poll
|
||||||
|
* = pollRepository.findBySlug(slug); if (poll == null) { return new
|
||||||
|
* ResponseEntity<>(HttpStatus.NOT_FOUND); } String filePath = "./Test.xls";
|
||||||
|
* //Utils.excel2pdf(); //convertToPdf(filePath); return
|
||||||
|
* getHttpEntityToDownload(filePath,"pdf"); }
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* private String convertToPdf(String filePath){ return "";
|
||||||
|
*
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int beginningColumnCell = 0;
|
||||||
|
static int beginningRowCell = 3;
|
||||||
|
static int fontSize = 9;
|
||||||
|
static Colour borderColour = Colour.WHITE;
|
||||||
|
|
||||||
|
private String createExcelFile(Poll poll, String slug) throws IOException {
|
||||||
|
DateFormat dateFormat = new SimpleDateFormat("dd.MM.yy-HH.mm.ss");
|
||||||
|
Date date = new Date();
|
||||||
|
String fileName = EXCEL_FILE_LOCATION + File.separator + slug + "-" + dateFormat.format(date) + ".xls";
|
||||||
|
|
||||||
|
File folder = new File(EXCEL_FILE_LOCATION);
|
||||||
|
if (!folder.exists()) {
|
||||||
|
folder.mkdir();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an Excel file
|
||||||
|
WritableWorkbook Wbook = null;
|
||||||
|
try {
|
||||||
|
System.out.println("Création du fichier");
|
||||||
|
// Create an Excel file in the file location
|
||||||
|
File file = new File(fileName);
|
||||||
|
|
||||||
|
if (!file.createNewFile()) {
|
||||||
|
System.out.println("Erreur lors de la création du fichier");
|
||||||
|
}
|
||||||
|
Wbook = Workbook.createWorkbook(file);
|
||||||
|
|
||||||
|
// Create an Excel sheet
|
||||||
|
WritableSheet mainSheet = Wbook.createSheet("SONDAGE", 0);
|
||||||
|
Wbook.setColourRGB(Colour.BLUE, 53, 37, 230);
|
||||||
|
|
||||||
|
// Format objects
|
||||||
|
WritableCellFormat formatTitle = new WritableCellFormat();
|
||||||
|
WritableFont fontTitle = new WritableFont(WritableFont.TAHOMA, 16, WritableFont.BOLD);
|
||||||
|
fontTitle.setColour(Colour.BLUE);
|
||||||
|
formatTitle.setFont(fontTitle);
|
||||||
|
|
||||||
|
Label label;
|
||||||
|
label = new Label(0, 0, "Sondage \"" + poll.getTitle() + "\"", formatTitle);
|
||||||
|
mainSheet.addCell(label);
|
||||||
|
label = new Label(0, 1, "http://localhost:3000/polls/" + poll.getSlug());
|
||||||
|
mainSheet.addCell(label);
|
||||||
|
|
||||||
|
// On récupere les users qui ont voté dans ce sondage
|
||||||
|
List<User> users = retrieveUsers(poll);
|
||||||
|
|
||||||
|
// On ecrit les users sur la première colonne
|
||||||
|
writeUsers(poll, Wbook, users);
|
||||||
|
|
||||||
|
// On ecrit les choix avec les votes de chaque users
|
||||||
|
writeChoices(poll, Wbook, users);
|
||||||
|
|
||||||
|
System.out.println("Enregistrement du fichier");
|
||||||
|
// On ecrit les donnée du workbook dans un format excel
|
||||||
|
Wbook.write();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("Erreur lors de la création du fichier :( " + e.toString());
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
|
||||||
|
if (Wbook != null) {
|
||||||
|
try {
|
||||||
|
Wbook.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<User> retrieveUsers(Poll poll) {
|
||||||
|
List<User> users = new ArrayList<>();
|
||||||
|
// On parcours les choix du poll pour récupérer les users ayant voté
|
||||||
|
if (!poll.getPollChoices().isEmpty()) {
|
||||||
|
for (Choice choice : poll.getPollChoices()) {
|
||||||
|
if (!choice.getUsers().isEmpty()) {
|
||||||
|
for (User user : choice.getUsers()) {
|
||||||
|
// On vérifie que le user ne soit pas déjà dans la liste
|
||||||
|
if (!users.contains(user)) {
|
||||||
|
users.add(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeChoices(Poll poll, WritableWorkbook Wbook, List<User> users) throws jxl.write.WriteException {
|
||||||
|
Label label;
|
||||||
|
Number number;
|
||||||
|
WritableSheet mainSheet = Wbook.getSheet(0);
|
||||||
|
|
||||||
|
List<fr.istic.tlc.domain.Choice> choices = poll.getPollChoices();
|
||||||
|
// List<Choice> choices =
|
||||||
|
// choiceRepository.findAll(Sort.by(Sort.Direction.ASC,"startDate"));
|
||||||
|
|
||||||
|
// Format objects
|
||||||
|
WritableCellFormat formatVoteYes = new WritableCellFormat();
|
||||||
|
formatVoteYes.setAlignment(Alignment.CENTRE);
|
||||||
|
formatVoteYes.setVerticalAlignment(VerticalAlignment.CENTRE);
|
||||||
|
formatVoteYes.setBorder(Border.ALL, BorderLineStyle.THIN, borderColour);
|
||||||
|
formatVoteYes.setBackground(Colour.LIGHT_GREEN);
|
||||||
|
WritableFont fontVoteYes = new WritableFont(WritableFont.TAHOMA, fontSize, WritableFont.NO_BOLD);
|
||||||
|
fontVoteYes.setColour(Colour.BLACK);
|
||||||
|
formatVoteYes.setFont(fontVoteYes);
|
||||||
|
// Format objects
|
||||||
|
Wbook.setColourRGB(Colour.LIGHT_ORANGE, 255, 195, 195);
|
||||||
|
WritableCellFormat formatVoteNo = new WritableCellFormat();
|
||||||
|
formatVoteNo.setAlignment(Alignment.CENTRE);
|
||||||
|
formatVoteNo.setVerticalAlignment(VerticalAlignment.CENTRE);
|
||||||
|
formatVoteNo.setBorder(Border.ALL, BorderLineStyle.THIN, borderColour);
|
||||||
|
formatVoteNo.setBackground(Colour.LIGHT_ORANGE);
|
||||||
|
WritableFont fontVoteNo = new WritableFont(WritableFont.TAHOMA, fontSize, WritableFont.NO_BOLD);
|
||||||
|
fontVoteNo.setColour(Colour.BLACK);
|
||||||
|
formatVoteNo.setFont(fontVoteNo);
|
||||||
|
|
||||||
|
// On ecrit les colonnes des choix
|
||||||
|
for (int i = 0; i < choices.size(); i++) {
|
||||||
|
mainSheet.setColumnView(1 + beginningColumnCell + i, 14);
|
||||||
|
// On ecrit la date
|
||||||
|
writeChoiceDate(Wbook, choices, i);
|
||||||
|
|
||||||
|
// On ecrit les votes
|
||||||
|
List<User> listUsersVotes = choices.get(i).getUsers();
|
||||||
|
for (int x = 0; x < users.size(); x++) {
|
||||||
|
if (listUsersVotes.contains(users.get(x))) {
|
||||||
|
label = new Label(1 + beginningColumnCell + i, 3 + beginningRowCell + x, "OK", formatVoteYes);
|
||||||
|
} else {
|
||||||
|
label = new Label(1 + beginningColumnCell + i, 3 + beginningRowCell + x, "-", formatVoteNo);
|
||||||
|
}
|
||||||
|
mainSheet.addCell(label);
|
||||||
|
}
|
||||||
|
// on ecrit le nombre total de vote pour le choix
|
||||||
|
number = new Number(1 + beginningColumnCell + i, 3 + beginningRowCell + users.size(),
|
||||||
|
listUsersVotes.size());
|
||||||
|
mainSheet.addCell(number);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeChoiceDate(WritableWorkbook Wbook, List<Choice> choices, int i) throws jxl.write.WriteException {
|
||||||
|
Label label;
|
||||||
|
WritableSheet mainSheet = Wbook.getSheet(0);
|
||||||
|
String month[] = { "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Aout", "Septembre",
|
||||||
|
"Novembre", "Décembre" };
|
||||||
|
String dayOfWeek[] = { "Lun.", "Mar.", "Mer.", "Jeu.", "Ven.", "Sam.", "Dim." };
|
||||||
|
Wbook.setColourRGB(Colour.BLUE, 53, 37, 230);
|
||||||
|
// Format objects
|
||||||
|
WritableCellFormat formatDate = new WritableCellFormat();
|
||||||
|
formatDate.setAlignment(Alignment.CENTRE);
|
||||||
|
formatDate.setVerticalAlignment(VerticalAlignment.CENTRE);
|
||||||
|
formatDate.setBorder(Border.ALL, BorderLineStyle.THIN, borderColour);
|
||||||
|
formatDate.setBackground(Colour.BLUE);
|
||||||
|
WritableFont fontDate = new WritableFont(WritableFont.TAHOMA, fontSize, WritableFont.NO_BOLD);
|
||||||
|
fontDate.setColour(Colour.WHITE);
|
||||||
|
formatDate.setFont(fontDate);
|
||||||
|
|
||||||
|
// On recupère la date de début
|
||||||
|
Choice choice = choices.get(i);
|
||||||
|
Date startDate = choice.getstartDate();
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
calendar.setTime(startDate);
|
||||||
|
int startYear = calendar.get(Calendar.YEAR);
|
||||||
|
String startMonth = month[calendar.get(Calendar.MONTH)];
|
||||||
|
int startDayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
|
||||||
|
String startDayOfWeek = dayOfWeek[calendar.get(Calendar.DAY_OF_WEEK) - 1];
|
||||||
|
int startHourInt = calendar.get(Calendar.HOUR_OF_DAY);
|
||||||
|
String startHour = (startHourInt < 10 ? "0" : "") + startHourInt;
|
||||||
|
int startMinuteInt = calendar.get(Calendar.MINUTE);
|
||||||
|
String startMinute = (startMinuteInt < 10 ? "0" : "") + startMinuteInt;
|
||||||
|
// On recupère la date de fin
|
||||||
|
Date endDate = choice.getendDate();
|
||||||
|
calendar.setTime(endDate);
|
||||||
|
int endHourInt = calendar.get(Calendar.HOUR_OF_DAY);
|
||||||
|
String endHour = (endHourInt < 10 ? "0" : "") + endHourInt;
|
||||||
|
int endMinuteInt = calendar.get(Calendar.MINUTE);
|
||||||
|
String endMinute = (endMinuteInt < 10 ? "0" : "") + endMinuteInt;
|
||||||
|
|
||||||
|
label = new Label(1 + beginningColumnCell + i, beginningRowCell, startMonth + " " + startYear, formatDate);
|
||||||
|
mainSheet.addCell(label);
|
||||||
|
label = new Label(1 + beginningColumnCell + i, 1 + beginningRowCell, startDayOfWeek + " " + startDayOfMonth,
|
||||||
|
formatDate);
|
||||||
|
mainSheet.addCell(label);
|
||||||
|
label = new Label(1 + beginningColumnCell + i, 2 + beginningRowCell,
|
||||||
|
startHour + ":" + startMinute + " - " + endHour + ":" + endMinute, formatDate);
|
||||||
|
mainSheet.addCell(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeUsers(Poll poll, WritableWorkbook Wbook, List<User> users) throws jxl.write.WriteException {
|
||||||
|
Label label;
|
||||||
|
|
||||||
|
WritableSheet mainSheet = Wbook.getSheet(0);
|
||||||
|
mainSheet.setColumnView(beginningColumnCell, 25);
|
||||||
|
|
||||||
|
// Format objects
|
||||||
|
WritableCellFormat formatUser = new WritableCellFormat();
|
||||||
|
formatUser.setAlignment(Alignment.RIGHT);
|
||||||
|
formatUser.setVerticalAlignment(VerticalAlignment.CENTRE);
|
||||||
|
formatUser.setBorder(Border.ALL, BorderLineStyle.THIN, borderColour);
|
||||||
|
|
||||||
|
formatUser.setBackground(Colour.GRAY_25);
|
||||||
|
WritableFont fontUser = new WritableFont(WritableFont.TAHOMA, fontSize, WritableFont.NO_BOLD);
|
||||||
|
fontUser.setColour(Colour.BLACK);
|
||||||
|
formatUser.setFont(fontUser);
|
||||||
|
|
||||||
|
// On ecrit la premier colonne avec users et label "Nombre"
|
||||||
|
for (int i = 0; i < users.size(); i++) {
|
||||||
|
label = new Label(beginningColumnCell, 3 + beginningRowCell + i, users.get(i).getUsername(), formatUser);
|
||||||
|
mainSheet.addCell(label);
|
||||||
|
}
|
||||||
|
label = new Label(beginningColumnCell, 3 + beginningRowCell + users.size(), "Nombre");
|
||||||
|
mainSheet.addCell(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Response getHttpEntityToDownload(String filePath, String fileType) throws IOException {
|
||||||
|
File file = getFile(filePath);
|
||||||
|
|
||||||
|
// header.set("Content-Disposition", "inline; filename=" + file.getName());
|
||||||
|
return Response.ok(((Object) file), MediaType.APPLICATION_OCTET_STREAM)
|
||||||
|
.header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"").build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private File getFile(String filePath) throws FileNotFoundException {
|
||||||
|
File file = new File(filePath);
|
||||||
|
if (!file.exists()) {
|
||||||
|
throw new FileNotFoundException("file with path: " + filePath + " was not found.");
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @ControllerAdvice public class GlobalExceptionHandler {
|
||||||
|
*
|
||||||
|
* @ExceptionHandler(value = FileNotFoundException.class) public void
|
||||||
|
* handle(FileNotFoundException ex, HttpServletResponse response) throws
|
||||||
|
* IOException { System.out.println("handling file not found exception");
|
||||||
|
* response.sendError(404, ex.getMessage()); }
|
||||||
|
*
|
||||||
|
* @ExceptionHandler(value = IOException.class) public void handle(IOException
|
||||||
|
* ex, HttpServletResponse response) throws IOException {
|
||||||
|
* System.out.println("handling io exception"); response.sendError(500,
|
||||||
|
* ex.getMessage()); } }
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package fr.istic.tlc.resources.itf;
|
||||||
|
|
||||||
|
|
||||||
|
import fr.istic.tlc.dao.ChoiceRepository;
|
||||||
|
import fr.istic.tlc.domain.Choice;
|
||||||
|
import io.quarkus.hibernate.orm.rest.data.panache.PanacheRepositoryResource;
|
||||||
|
import io.quarkus.rest.data.panache.ResourceProperties;
|
||||||
|
|
||||||
|
@ResourceProperties(path = "/api/choice")
|
||||||
|
public interface ChoiceResource extends PanacheRepositoryResource<ChoiceRepository, Choice,Long> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package fr.istic.tlc.resources.itf;
|
||||||
|
|
||||||
|
import fr.istic.tlc.dao.CommentRepository;
|
||||||
|
import fr.istic.tlc.domain.Comment;
|
||||||
|
import io.quarkus.hibernate.orm.rest.data.panache.PanacheRepositoryResource;
|
||||||
|
import io.quarkus.rest.data.panache.ResourceProperties;
|
||||||
|
|
||||||
|
@ResourceProperties(path = "/api/comment")
|
||||||
|
public interface CommentResource extends PanacheRepositoryResource<CommentRepository, Comment,Long> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package fr.istic.tlc.resources.itf;
|
||||||
|
|
||||||
|
import fr.istic.tlc.dao.MealPreferenceRepository;
|
||||||
|
import fr.istic.tlc.domain.MealPreference;
|
||||||
|
import io.quarkus.hibernate.orm.rest.data.panache.PanacheRepositoryResource;
|
||||||
|
import io.quarkus.rest.data.panache.ResourceProperties;
|
||||||
|
|
||||||
|
@ResourceProperties(path = "/api/mealpreference")
|
||||||
|
public interface MealPreferenceResource extends PanacheRepositoryResource<MealPreferenceRepository,MealPreference,Long> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package fr.istic.tlc.resources.itf;
|
||||||
|
|
||||||
|
import fr.istic.tlc.dao.PollRepository;
|
||||||
|
import fr.istic.tlc.domain.Poll;
|
||||||
|
import io.quarkus.hibernate.orm.rest.data.panache.PanacheRepositoryResource;
|
||||||
|
import io.quarkus.rest.data.panache.ResourceProperties;
|
||||||
|
|
||||||
|
@ResourceProperties(path = "/api/poll")
|
||||||
|
public interface PollResource extends PanacheRepositoryResource<PollRepository, Poll,Long> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package fr.istic.tlc.resources.itf;
|
||||||
|
|
||||||
|
import fr.istic.tlc.dao.UserRepository;
|
||||||
|
import fr.istic.tlc.domain.User;
|
||||||
|
import io.quarkus.hibernate.orm.rest.data.panache.PanacheRepositoryResource;
|
||||||
|
import io.quarkus.rest.data.panache.ResourceProperties;
|
||||||
|
|
||||||
|
@ResourceProperties(path = "/api/user")
|
||||||
|
public interface UserResource extends PanacheRepositoryResource<UserRepository, User,Long> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
package fr.istic.tlc.services;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
|
||||||
|
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
||||||
|
|
||||||
|
import fr.istic.tlc.dao.PollRepository;
|
||||||
|
import fr.istic.tlc.domain.Poll;
|
||||||
|
import fr.istic.tlc.domain.User;
|
||||||
|
import io.quarkus.mailer.Mail;
|
||||||
|
import io.quarkus.mailer.Mailer;
|
||||||
|
import net.fortuna.ical4j.model.DateTime;
|
||||||
|
import net.fortuna.ical4j.model.TimeZone;
|
||||||
|
import net.fortuna.ical4j.model.TimeZoneRegistry;
|
||||||
|
import net.fortuna.ical4j.model.TimeZoneRegistryFactory;
|
||||||
|
import net.fortuna.ical4j.model.component.VEvent;
|
||||||
|
import net.fortuna.ical4j.model.component.VTimeZone;
|
||||||
|
import net.fortuna.ical4j.model.parameter.Role;
|
||||||
|
import net.fortuna.ical4j.model.property.Attendee;
|
||||||
|
import net.fortuna.ical4j.model.property.CalScale;
|
||||||
|
import net.fortuna.ical4j.model.property.Method;
|
||||||
|
import net.fortuna.ical4j.model.property.Organizer;
|
||||||
|
import net.fortuna.ical4j.model.property.ProdId;
|
||||||
|
import net.fortuna.ical4j.model.property.Uid;
|
||||||
|
import net.fortuna.ical4j.model.property.Version;
|
||||||
|
import net.fortuna.ical4j.util.MapTimeZoneCache;
|
||||||
|
import net.fortuna.ical4j.util.RandomUidGenerator;
|
||||||
|
import net.fortuna.ical4j.util.UidGenerator;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class SendEmail {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
Mailer mailer;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
PollRepository pollRep;
|
||||||
|
|
||||||
|
@ConfigProperty(name = "doodle.organizermail")
|
||||||
|
String organizermail= "test@test.fr";
|
||||||
|
public void sendASimpleEmail(Poll p ) {
|
||||||
|
// Create a default MimeMessage object.
|
||||||
|
System.setProperty("net.fortuna.ical4j.timezone.cache.impl", MapTimeZoneCache.class.getName());
|
||||||
|
|
||||||
|
List<User> u = this.pollRep.findAllUser4Poll(p.getId());
|
||||||
|
List<String> attendees = new ArrayList<String>();
|
||||||
|
for (User u1 : u) {
|
||||||
|
attendees.add(u1.getMail());
|
||||||
|
}
|
||||||
|
|
||||||
|
String ics = this.getICS1(p.getSelectedChoice().getstartDate(), p.getSelectedChoice().getendDate(), p.getTitle(), attendees, organizermail);
|
||||||
|
Mail m = new Mail();
|
||||||
|
m.addAttachment("meeting.ics", ics.getBytes(), "text/calendar");
|
||||||
|
|
||||||
|
m.setFrom(organizermail);
|
||||||
|
m.setTo(attendees);
|
||||||
|
m.setCc(Arrays.asList(organizermail));
|
||||||
|
m.setFrom(organizermail);
|
||||||
|
m.setSubject("Réunion c" + p.getTitle() + " [créneau confirmé] ");
|
||||||
|
m.setHtml("La date définitive pour la réunion : \""+ p.getTitle() + "\" a été validée par l\'organisateur. <BR>" +
|
||||||
|
"Un salon a été créé de discussion pour cette réunion est accessible à cette adresse <a [href]=\" " +p.getTlkURL() + "\" target=\"_blank\">" + p.getTlkURL() + "</a>.<BR>\n" +
|
||||||
|
"Un pad a été créé pour cette réunion <a [href]=\""+ p.getPadURL() + "\" target=\"_blank\">\""+ p.getPadURL() + "\"</a>.</span><BR>\n");
|
||||||
|
|
||||||
|
mailer.send(m);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getICS1(Date start, Date end, String libelle, List<String> attendees, String organizer) {
|
||||||
|
|
||||||
|
// Create a TimeZone
|
||||||
|
TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry();
|
||||||
|
TimeZone timezone = registry.getTimeZone("Europe/Paris");
|
||||||
|
VTimeZone tz = timezone.getVTimeZone();
|
||||||
|
|
||||||
|
// Create the event
|
||||||
|
DateTime startd = new DateTime(start);
|
||||||
|
DateTime endd = new DateTime(end);
|
||||||
|
VEvent meeting = new VEvent(startd, endd, libelle);
|
||||||
|
// add timezone info..
|
||||||
|
meeting.getProperties().add(tz.getTimeZoneId());
|
||||||
|
|
||||||
|
// generate unique identifier..
|
||||||
|
UidGenerator ug = new RandomUidGenerator();
|
||||||
|
Uid uid = ug.generateUid();
|
||||||
|
meeting.getProperties().add(uid);
|
||||||
|
|
||||||
|
|
||||||
|
// add attendees..
|
||||||
|
for (String attendee : attendees) {
|
||||||
|
Attendee p1 = new Attendee(URI.create("mailto:"+attendee));
|
||||||
|
p1.getParameters().add(Role.REQ_PARTICIPANT);
|
||||||
|
// dev1.getParameters().add(new Cn("Developer 1"));
|
||||||
|
meeting.getProperties().add(p1);
|
||||||
|
}
|
||||||
|
Organizer p1 = new Organizer(URI.create("mailto:"+organizer));
|
||||||
|
meeting.getProperties().add(p1);
|
||||||
|
|
||||||
|
|
||||||
|
// Create a calendar
|
||||||
|
net.fortuna.ical4j.model.Calendar icsCalendar = new net.fortuna.ical4j.model.Calendar();
|
||||||
|
icsCalendar.getProperties().add(Version.VERSION_2_0);
|
||||||
|
icsCalendar.getProperties().add(new ProdId("Zimbra-Calendar-Provider"));
|
||||||
|
icsCalendar.getProperties().add(CalScale.GREGORIAN);
|
||||||
|
icsCalendar.getProperties().add(Method.REQUEST);
|
||||||
|
icsCalendar.getComponents().add(tz);
|
||||||
|
|
||||||
|
// Add the event and print
|
||||||
|
icsCalendar.getComponents().add(meeting);
|
||||||
|
|
||||||
|
return icsCalendar.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package fr.istic.tlc.services;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class Utils {
|
||||||
|
private Random random = null;// = new Random();
|
||||||
|
private static final String CHARS = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ234567890";
|
||||||
|
private static Utils instance = null;
|
||||||
|
private Utils(){
|
||||||
|
this.random = new Random();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static Utils getInstance(){
|
||||||
|
if (instance == null)
|
||||||
|
instance = new Utils();
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String generateSlug(int length) {
|
||||||
|
if (random == null){
|
||||||
|
random = new Random();
|
||||||
|
}
|
||||||
|
StringBuilder slug = new StringBuilder(length);
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
slug.append(CHARS.charAt(random.nextInt(CHARS.length())));
|
||||||
|
}
|
||||||
|
return slug.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean intersect(Date start1, Date end1, Date start2, Date end2) {
|
||||||
|
if (start1 == null || start2 == null ||end1 == null||end2 == null)
|
||||||
|
return false;
|
||||||
|
return end1.after(start2) && start1.before(end2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,34 @@
|
|||||||
|
doodle:
|
||||||
|
usepad: true
|
||||||
|
internalPadUrl: "http://localhost:9001/"
|
||||||
|
externalPadUrl: "http://localhost:9001/"
|
||||||
|
padApiKey: "19d89ca52bc0fa4f19d6325464d9d7a032649b9fa68c111514627081e2784b4a"
|
||||||
|
organizermail: "olivier.barais@gmail.com"
|
||||||
|
tmpfolder: "/tmp/excelFiles"
|
||||||
|
quarkus:
|
||||||
|
datasource:
|
||||||
|
db-kind: mysql
|
||||||
|
username: tlc
|
||||||
|
password: tlc
|
||||||
|
jdbc:
|
||||||
|
url: jdbc:mysql://localhost:3306/tlc?useUnicode=true&serverTimezone=Europe/Paris
|
||||||
|
driver: com.mysql.cj.jdbc.Driver
|
||||||
|
hibernate-orm:
|
||||||
|
validate-in-dev-mode: false
|
||||||
|
# flyway:
|
||||||
|
# migrate-at-start: true
|
||||||
|
# baseline-on-migrate: true
|
||||||
|
database:
|
||||||
|
generation: update
|
||||||
|
globally-quoted-identifiers: true
|
||||||
|
mailer:
|
||||||
|
from: test@quarkus.io
|
||||||
|
# host: smtp.sendgrid.net
|
||||||
|
host: localhost
|
||||||
|
port: 2525
|
||||||
|
# port: 465
|
||||||
|
# ssl: true
|
||||||
|
|
||||||
|
# username: ""
|
||||||
|
# password: ""
|
||||||
|
mock: false
|
||||||
@@ -0,0 +1,294 @@
|
|||||||
|
-- phpMyAdmin SQL Dump
|
||||||
|
-- version 5.1.1deb5ubuntu1
|
||||||
|
-- https://www.phpmyadmin.net/
|
||||||
|
--
|
||||||
|
-- Hôte : localhost:3306
|
||||||
|
-- Généré le : mar. 22 août 2023 à 10:08
|
||||||
|
-- Version du serveur : 8.0.33-0ubuntu0.22.04.4
|
||||||
|
-- Version de PHP : 8.1.2-1ubuntu2.13
|
||||||
|
|
||||||
|
|
||||||
|
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
|
||||||
|
SET AUTOCOMMIT = 0;
|
||||||
|
START TRANSACTION;
|
||||||
|
SET time_zone = "+00:00";
|
||||||
|
|
||||||
|
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||||
|
/*!40101 SET NAMES utf8mb4 */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Base de données : `tlc`
|
||||||
|
--
|
||||||
|
CREATE DATABASE IF NOT EXISTS `tlc` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
|
||||||
|
USE `tlc`;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||||
|
/*!40101 SET NAMES utf8mb4 */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Base de données : `tlc`
|
||||||
|
--
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Structure de la table `Choice`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `Choice` (
|
||||||
|
`id` bigint NOT NULL,
|
||||||
|
`endDate` datetime(6) DEFAULT NULL,
|
||||||
|
`startDate` datetime(6) DEFAULT NULL,
|
||||||
|
`pollID` bigint DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Structure de la table `Choice_SEQ`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `Choice_SEQ` (
|
||||||
|
`next_val` bigint DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Déchargement des données de la table `Choice_SEQ`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `Choice_SEQ` (`next_val`) VALUES
|
||||||
|
(1);
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Structure de la table `choice_user`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `choice_user` (
|
||||||
|
`choice_id` bigint NOT NULL,
|
||||||
|
`user_id` bigint NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Structure de la table `Comment`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `Comment` (
|
||||||
|
`id` bigint NOT NULL,
|
||||||
|
`auteur` varchar(255) DEFAULT NULL,
|
||||||
|
`content` varchar(255) DEFAULT NULL,
|
||||||
|
`pollID` bigint DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Structure de la table `Comment_SEQ`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `Comment_SEQ` (
|
||||||
|
`next_val` bigint DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Déchargement des données de la table `Comment_SEQ`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `Comment_SEQ` (`next_val`) VALUES
|
||||||
|
(1);
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Structure de la table `MealPreference`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `MealPreference` (
|
||||||
|
`id` bigint NOT NULL,
|
||||||
|
`content` varchar(255) DEFAULT NULL,
|
||||||
|
`user_id` bigint DEFAULT NULL,
|
||||||
|
`pollID` bigint DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Structure de la table `MealPreference_SEQ`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `MealPreference_SEQ` (
|
||||||
|
`next_val` bigint DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Déchargement des données de la table `MealPreference_SEQ`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `MealPreference_SEQ` (`next_val`) VALUES
|
||||||
|
(1);
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Structure de la table `Poll`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `Poll` (
|
||||||
|
`id` bigint NOT NULL,
|
||||||
|
`clos` bit(1) NOT NULL,
|
||||||
|
`createdAt` datetime(6) DEFAULT NULL,
|
||||||
|
`description` varchar(255) DEFAULT NULL,
|
||||||
|
`has_meal` bit(1) NOT NULL,
|
||||||
|
`location` varchar(255) DEFAULT NULL,
|
||||||
|
`padURL` varchar(255) DEFAULT NULL,
|
||||||
|
`slug` varchar(255) DEFAULT NULL,
|
||||||
|
`slugAdmin` varchar(255) DEFAULT NULL,
|
||||||
|
`title` varchar(255) DEFAULT NULL,
|
||||||
|
`tlkURL` varchar(255) DEFAULT NULL,
|
||||||
|
`updatedAt` datetime(6) DEFAULT NULL,
|
||||||
|
`selectedChoice_id` bigint DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Structure de la table `Poll_SEQ`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `Poll_SEQ` (
|
||||||
|
`next_val` bigint DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Déchargement des données de la table `Poll_SEQ`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `Poll_SEQ` (`next_val`) VALUES
|
||||||
|
(1);
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Structure de la table `User`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `User` (
|
||||||
|
`id` bigint NOT NULL,
|
||||||
|
`icsurl` varchar(255) DEFAULT NULL,
|
||||||
|
`mail` varchar(255) DEFAULT NULL,
|
||||||
|
`username` varchar(255) DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Structure de la table `User_SEQ`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `User_SEQ` (
|
||||||
|
`next_val` bigint DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Déchargement des données de la table `User_SEQ`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `User_SEQ` (`next_val`) VALUES
|
||||||
|
(1);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Index pour les tables déchargées
|
||||||
|
--
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Index pour la table `Choice`
|
||||||
|
--
|
||||||
|
ALTER TABLE `Choice`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD KEY `FKpptbydus718x0n5w5s1hmtvnp` (`pollID`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Index pour la table `choice_user`
|
||||||
|
--
|
||||||
|
ALTER TABLE `choice_user`
|
||||||
|
ADD KEY `FK74lqrm3h9f56d6ijnvjobl0wb` (`user_id`),
|
||||||
|
ADD KEY `FKljka9n83yo9s4qpol3wplp1lw` (`choice_id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Index pour la table `Comment`
|
||||||
|
--
|
||||||
|
ALTER TABLE `Comment`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD KEY `FKgw1unu5kgu9s7sdkqaoy0kyyh` (`pollID`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Index pour la table `MealPreference`
|
||||||
|
--
|
||||||
|
ALTER TABLE `MealPreference`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD KEY `FK61nykkil19yk0on84o44ykk3p` (`user_id`),
|
||||||
|
ADD KEY `FK9pk3lx8mh8478nxj8lvxvaox0` (`pollID`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Index pour la table `Poll`
|
||||||
|
--
|
||||||
|
ALTER TABLE `Poll`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `UK_n779urxmh62kwbspgd6gp8564` (`selectedChoice_id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Index pour la table `User`
|
||||||
|
--
|
||||||
|
ALTER TABLE `User`
|
||||||
|
ADD PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Contraintes pour les tables déchargées
|
||||||
|
--
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Contraintes pour la table `Choice`
|
||||||
|
--
|
||||||
|
ALTER TABLE `Choice`
|
||||||
|
ADD CONSTRAINT `FKpptbydus718x0n5w5s1hmtvnp` FOREIGN KEY (`pollID`) REFERENCES `Poll` (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Contraintes pour la table `choice_user`
|
||||||
|
--
|
||||||
|
ALTER TABLE `choice_user`
|
||||||
|
ADD CONSTRAINT `FK74lqrm3h9f56d6ijnvjobl0wb` FOREIGN KEY (`user_id`) REFERENCES `User` (`id`),
|
||||||
|
ADD CONSTRAINT `FKljka9n83yo9s4qpol3wplp1lw` FOREIGN KEY (`choice_id`) REFERENCES `Choice` (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Contraintes pour la table `Comment`
|
||||||
|
--
|
||||||
|
ALTER TABLE `Comment`
|
||||||
|
ADD CONSTRAINT `FKgw1unu5kgu9s7sdkqaoy0kyyh` FOREIGN KEY (`pollID`) REFERENCES `Poll` (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Contraintes pour la table `MealPreference`
|
||||||
|
--
|
||||||
|
ALTER TABLE `MealPreference`
|
||||||
|
ADD CONSTRAINT `FK61nykkil19yk0on84o44ykk3p` FOREIGN KEY (`user_id`) REFERENCES `User` (`id`),
|
||||||
|
ADD CONSTRAINT `FK9pk3lx8mh8478nxj8lvxvaox0` FOREIGN KEY (`pollID`) REFERENCES `Poll` (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Contraintes pour la table `Poll`
|
||||||
|
--
|
||||||
|
ALTER TABLE `Poll`
|
||||||
|
ADD CONSTRAINT `FKfdictafwo8dwab5rjrjkmmxri` FOREIGN KEY (`selectedChoice_id`) REFERENCES `Choice` (`id`);
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#
|
||||||
|
# Licensed to Apereo under one or more contributor license
|
||||||
|
# agreements. See the NOTICE file distributed with this work
|
||||||
|
# for additional information regarding copyright ownership.
|
||||||
|
# Apereo licenses this file to you under the Apache License,
|
||||||
|
# Version 2.0 (the "License"); you may not use this file
|
||||||
|
# except in compliance with the License. You may obtain a
|
||||||
|
# copy of the License at the following location:
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing,
|
||||||
|
# software distributed under the License is distributed on an
|
||||||
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
# KIND, either express or implied. See the License for the
|
||||||
|
# specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
# Known optional properties for ical4j:
|
||||||
|
#net.fortuna.ical4j.parser=net.fortuna.ical4j.data.HCalendarParserFactory
|
||||||
|
#net.fortuna.ical4j.timezone.registry=net.fortuna.ical4j.model.DefaultTimeZoneRegistryFactory
|
||||||
|
#net.fortuna.ical4j.timezone.update.enabled={true|false}
|
||||||
|
#net.fortuna.ical4j.timezone.date.floating={true|false}
|
||||||
|
#net.fortuna.ical4j.factory.decoder=net.fortuna.ical4j.util.DefaultDecoderFactory
|
||||||
|
#net.fortuna.ical4j.factory.encoder=net.fortuna.ical4j.util.DefaultEncoderFactory
|
||||||
|
#net.fortuna.ical4j.recur.maxincrementcount=1000
|
||||||
|
#ical4j.unfolding.relaxed={true|false}
|
||||||
|
#ical4j.parsing.relaxed={true|false}
|
||||||
|
#ical4j.validation.relaxed={true|false}
|
||||||
|
#ical4j.compatibility.outlook={true|false}
|
||||||
|
#ical4j.compatibility.notes={true|false}
|
||||||
|
|
||||||
|
# Values...
|
||||||
|
ical4j.unfolding.relaxed=true
|
||||||
|
ical4j.compatibility.outlook=true
|
||||||
|
ical4j.compatibility.notes=true
|
||||||
|
ical4j.parsing.relaxed=true
|
||||||
|
ical4j.validation.relaxed=true
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name" : "net.fortuna.ical4j.util.JCacheTimeZoneCache",
|
||||||
|
"allDeclaredConstructors" : true,
|
||||||
|
"allPublicConstructors" : true,
|
||||||
|
"allDeclaredMethods" : true,
|
||||||
|
"allPublicMethods" : true,
|
||||||
|
"allDeclaredFields" : true,
|
||||||
|
"allPublicFields" : true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "net.fortuna.ical4j.util.MapTimeZoneCache",
|
||||||
|
"allDeclaredConstructors" : true,
|
||||||
|
"allPublicConstructors" : true,
|
||||||
|
"allDeclaredMethods" : true,
|
||||||
|
"allPublicMethods" : true,
|
||||||
|
"allDeclaredFields" : true,
|
||||||
|
"allPublicFields" : true
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
18
ansible/files/doodlestudent/front/.browserslistrc
Normal file
18
ansible/files/doodlestudent/front/.browserslistrc
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||||
|
# For additional information regarding the format and rule options, please see:
|
||||||
|
# https://github.com/browserslist/browserslist#queries
|
||||||
|
|
||||||
|
# For the full list of supported browsers by the Angular framework, please see:
|
||||||
|
# https://angular.io/guide/browser-support
|
||||||
|
|
||||||
|
# You can see what browsers were selected by your queries by running:
|
||||||
|
# npx browserslist
|
||||||
|
|
||||||
|
last 1 Chrome version
|
||||||
|
last 1 Firefox version
|
||||||
|
last 2 Edge major versions
|
||||||
|
last 2 Safari major versions
|
||||||
|
last 2 iOS major versions
|
||||||
|
Firefox ESR
|
||||||
|
not IE 9-10 # Angular support for IE 9-10 has been deprecated and will be removed as of Angular v11. To opt-in, remove the 'not' prefix on this line.
|
||||||
|
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
|
||||||
16
ansible/files/doodlestudent/front/.editorconfig
Normal file
16
ansible/files/doodlestudent/front/.editorconfig
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Editor configuration, see https://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.ts]
|
||||||
|
quote_type = single
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
max_line_length = off
|
||||||
|
trim_trailing_whitespace = false
|
||||||
46
ansible/files/doodlestudent/front/.gitignore
vendored
Normal file
46
ansible/files/doodlestudent/front/.gitignore
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# compiled output
|
||||||
|
/dist
|
||||||
|
/tmp
|
||||||
|
/out-tsc
|
||||||
|
# Only exists if Bazel was run
|
||||||
|
/bazel-out
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
|
||||||
|
# profiling files
|
||||||
|
chrome-profiler-events*.json
|
||||||
|
speed-measure-plugin*.json
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
/.idea
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# IDE - VSCode
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.history/*
|
||||||
|
|
||||||
|
# misc
|
||||||
|
/.sass-cache
|
||||||
|
/connect.lock
|
||||||
|
/coverage
|
||||||
|
/libpeerconnection.log
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
testem.log
|
||||||
|
/typings
|
||||||
|
|
||||||
|
# System Files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
27
ansible/files/doodlestudent/front/README.md
Normal file
27
ansible/files/doodlestudent/front/README.md
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Tlcfront
|
||||||
|
|
||||||
|
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 10.1.7.
|
||||||
|
|
||||||
|
## Development server
|
||||||
|
|
||||||
|
Run `npm start` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||||
|
|
||||||
|
## Code scaffolding
|
||||||
|
|
||||||
|
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
|
||||||
|
|
||||||
|
## Running unit tests
|
||||||
|
|
||||||
|
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||||
|
|
||||||
|
## Running end-to-end tests
|
||||||
|
|
||||||
|
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||||
|
|
||||||
|
## Further help
|
||||||
|
|
||||||
|
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
||||||
29
ansible/files/doodlestudent/front/TODO.md
Normal file
29
ansible/files/doodlestudent/front/TODO.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
## TODO
|
||||||
|
|
||||||
|
[X] nombre de participants dans la vue edit
|
||||||
|
[X] Vue Admin
|
||||||
|
[X] Selection date retenue
|
||||||
|
[X] Sondage clos dans la vue edit et admin
|
||||||
|
[X] Modification par admin d'un doodle en cours
|
||||||
|
[X] Chargement ics externe dans la vue edit calendrier
|
||||||
|
[X] Import ICS coté serveur et complétion automatique des dispos
|
||||||
|
[X] Test Chargement ics externe dans la vue edit calendrier
|
||||||
|
[X] ICS avec évènement à répétition
|
||||||
|
[X] Date sur plusieurs jours
|
||||||
|
[X] Date journée entière
|
||||||
|
[X] Menu dans la vue admin pour edit, export
|
||||||
|
[X] Réintégration etherpad avec prop dans le fichier de conf
|
||||||
|
[X] Réintégration export Excel
|
||||||
|
[X] Affichage TalTo et Pad si not null
|
||||||
|
[X] Affichage commentaire
|
||||||
|
[X] envoie de mail avec ics
|
||||||
|
[X] Test envoi de mail avec ics à la cloture du poll
|
||||||
|
[X] Figé le poll séléctionné quand poll séléction date poll validé
|
||||||
|
[X] Chargement ICS dans la vue createPoll
|
||||||
|
[ ] Test etherpad client
|
||||||
|
|
||||||
|
[ ] Modification par un utilisateur des données déjà rentrées pour un poll
|
||||||
|
[ ] Gestion du choix peut être (relation suppléméntaire entre choice et user)
|
||||||
|
[ ] DSL pour la sélection automatique des plages libres à la création d'un poll
|
||||||
|
[ ] Vue mensuel
|
||||||
|
[ ] Sécurité SlugAdmin envoyé uniquement
|
||||||
131
ansible/files/doodlestudent/front/angular.json
Normal file
131
ansible/files/doodlestudent/front/angular.json
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
{
|
||||||
|
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||||
|
"version": 1,
|
||||||
|
"newProjectRoot": "projects",
|
||||||
|
"projects": {
|
||||||
|
"tlcfront": {
|
||||||
|
"projectType": "application",
|
||||||
|
"schematics": {},
|
||||||
|
"root": "",
|
||||||
|
"sourceRoot": "src",
|
||||||
|
"prefix": "app",
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-angular:browser",
|
||||||
|
"options": {
|
||||||
|
"outputPath": "dist/tlcfront",
|
||||||
|
"index": "src/index.html",
|
||||||
|
"main": "src/main.ts",
|
||||||
|
"polyfills": "src/polyfills.ts",
|
||||||
|
"tsConfig": "tsconfig.app.json",
|
||||||
|
"aot": true,
|
||||||
|
"assets": [
|
||||||
|
"src/favicon.ico",
|
||||||
|
"src/assets"
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"./node_modules/bootstrap/dist/css/bootstrap.css",
|
||||||
|
"node_modules/primeng/resources/themes/bootstrap4-light-blue/theme.css",
|
||||||
|
"node_modules/primeicons/primeicons.css",
|
||||||
|
"node_modules/primeng/resources/primeng.min.css",
|
||||||
|
"src/styles.css"
|
||||||
|
],
|
||||||
|
"scripts": [
|
||||||
|
"./node_modules/jquery/dist/jquery.js",
|
||||||
|
"./node_modules/bootstrap/dist/js/bootstrap.js"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "src/environments/environment.ts",
|
||||||
|
"with": "src/environments/environment.prod.ts"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"optimization": true,
|
||||||
|
"outputHashing": "all",
|
||||||
|
"sourceMap": false,
|
||||||
|
"extractCss": true,
|
||||||
|
"namedChunks": false,
|
||||||
|
"extractLicenses": true,
|
||||||
|
"vendorChunk": false,
|
||||||
|
"buildOptimizer": true,
|
||||||
|
"budgets": [
|
||||||
|
{
|
||||||
|
"type": "initial",
|
||||||
|
"maximumWarning": "2mb",
|
||||||
|
"maximumError": "5mb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "anyComponentStyle",
|
||||||
|
"maximumWarning": "6kb",
|
||||||
|
"maximumError": "10kb"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"serve": {
|
||||||
|
"builder": "@angular-devkit/build-angular:dev-server",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "tlcfront:build"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"browserTarget": "tlcfront:build:production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extract-i18n": {
|
||||||
|
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "tlcfront:build"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
|
"options": {
|
||||||
|
"main": "src/test.ts",
|
||||||
|
"polyfills": "src/polyfills.ts",
|
||||||
|
"tsConfig": "tsconfig.spec.json",
|
||||||
|
"karmaConfig": "karma.conf.js",
|
||||||
|
"assets": [
|
||||||
|
"src/favicon.ico",
|
||||||
|
"src/assets"
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"src/styles.css"
|
||||||
|
],
|
||||||
|
"scripts": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": [
|
||||||
|
"tsconfig.app.json",
|
||||||
|
"tsconfig.spec.json",
|
||||||
|
"e2e/tsconfig.json"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"e2e": {
|
||||||
|
"builder": "@angular-devkit/build-angular:protractor",
|
||||||
|
"options": {
|
||||||
|
"protractorConfig": "e2e/protractor.conf.js",
|
||||||
|
"devServerTarget": "tlcfront:serve"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"devServerTarget": "tlcfront:serve:production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}},
|
||||||
|
"defaultProject": "tlcfront"
|
||||||
|
}
|
||||||
36
ansible/files/doodlestudent/front/e2e/protractor.conf.js
Normal file
36
ansible/files/doodlestudent/front/e2e/protractor.conf.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// @ts-check
|
||||||
|
// Protractor configuration file, see link for more information
|
||||||
|
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||||
|
|
||||||
|
const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type { import("protractor").Config }
|
||||||
|
*/
|
||||||
|
exports.config = {
|
||||||
|
allScriptsTimeout: 11000,
|
||||||
|
specs: [
|
||||||
|
'./src/**/*.e2e-spec.ts'
|
||||||
|
],
|
||||||
|
capabilities: {
|
||||||
|
browserName: 'chrome'
|
||||||
|
},
|
||||||
|
directConnect: true,
|
||||||
|
baseUrl: 'http://localhost:4200/',
|
||||||
|
framework: 'jasmine',
|
||||||
|
jasmineNodeOpts: {
|
||||||
|
showColors: true,
|
||||||
|
defaultTimeoutInterval: 30000,
|
||||||
|
print: function() {}
|
||||||
|
},
|
||||||
|
onPrepare() {
|
||||||
|
require('ts-node').register({
|
||||||
|
project: require('path').join(__dirname, './tsconfig.json')
|
||||||
|
});
|
||||||
|
jasmine.getEnv().addReporter(new SpecReporter({
|
||||||
|
spec: {
|
||||||
|
displayStacktrace: StacktraceOption.PRETTY
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
23
ansible/files/doodlestudent/front/e2e/src/app.e2e-spec.ts
Normal file
23
ansible/files/doodlestudent/front/e2e/src/app.e2e-spec.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { AppPage } from './app.po';
|
||||||
|
import { browser, logging } from 'protractor';
|
||||||
|
|
||||||
|
describe('workspace-project App', () => {
|
||||||
|
let page: AppPage;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
page = new AppPage();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display welcome message', () => {
|
||||||
|
page.navigateTo();
|
||||||
|
expect(page.getTitleText()).toEqual('tlcfront app is running!');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
// Assert that there are no errors emitted from the browser
|
||||||
|
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
|
||||||
|
expect(logs).not.toContain(jasmine.objectContaining({
|
||||||
|
level: logging.Level.SEVERE,
|
||||||
|
} as logging.Entry));
|
||||||
|
});
|
||||||
|
});
|
||||||
11
ansible/files/doodlestudent/front/e2e/src/app.po.ts
Normal file
11
ansible/files/doodlestudent/front/e2e/src/app.po.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { browser, by, element } from 'protractor';
|
||||||
|
|
||||||
|
export class AppPage {
|
||||||
|
navigateTo(): Promise<unknown> {
|
||||||
|
return browser.get(browser.baseUrl) as Promise<unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTitleText(): Promise<string> {
|
||||||
|
return element(by.css('app-root .content span')).getText() as Promise<string>;
|
||||||
|
}
|
||||||
|
}
|
||||||
14
ansible/files/doodlestudent/front/e2e/tsconfig.json
Normal file
14
ansible/files/doodlestudent/front/e2e/tsconfig.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../out-tsc/e2e",
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es2018",
|
||||||
|
"types": [
|
||||||
|
"jasmine",
|
||||||
|
"jasminewd2",
|
||||||
|
"node"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
32
ansible/files/doodlestudent/front/karma.conf.js
Normal file
32
ansible/files/doodlestudent/front/karma.conf.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// Karma configuration file, see link for more information
|
||||||
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||||
|
|
||||||
|
module.exports = function (config) {
|
||||||
|
config.set({
|
||||||
|
basePath: '',
|
||||||
|
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||||
|
plugins: [
|
||||||
|
require('karma-jasmine'),
|
||||||
|
require('karma-chrome-launcher'),
|
||||||
|
require('karma-jasmine-html-reporter'),
|
||||||
|
require('karma-coverage-istanbul-reporter'),
|
||||||
|
require('@angular-devkit/build-angular/plugins/karma')
|
||||||
|
],
|
||||||
|
client: {
|
||||||
|
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||||
|
},
|
||||||
|
coverageIstanbulReporter: {
|
||||||
|
dir: require('path').join(__dirname, './coverage/tlcfront'),
|
||||||
|
reports: ['html', 'lcovonly', 'text-summary'],
|
||||||
|
fixWebpackSourcePaths: true
|
||||||
|
},
|
||||||
|
reporters: ['progress', 'kjhtml'],
|
||||||
|
port: 9876,
|
||||||
|
colors: true,
|
||||||
|
logLevel: config.LOG_INFO,
|
||||||
|
autoWatch: true,
|
||||||
|
browsers: ['Chrome'],
|
||||||
|
singleRun: false,
|
||||||
|
restartOnFileChange: true
|
||||||
|
});
|
||||||
|
};
|
||||||
13960
ansible/files/doodlestudent/front/package-lock.json
generated
Normal file
13960
ansible/files/doodlestudent/front/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
57
ansible/files/doodlestudent/front/package.json
Normal file
57
ansible/files/doodlestudent/front/package.json
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"name": "tlcfront",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"ng": "ng",
|
||||||
|
"start": "ng serve --proxy-config proxy.conf.json",
|
||||||
|
"build": "ng build",
|
||||||
|
"test": "ng test",
|
||||||
|
"lint": "ng lint",
|
||||||
|
"e2e": "ng e2e"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@angular/animations": "16.2.1",
|
||||||
|
"@angular/common": "16.2.1",
|
||||||
|
"@angular/compiler": "16.2.1",
|
||||||
|
"@angular/core": "16.2.1",
|
||||||
|
"@angular/forms": "16.2.1",
|
||||||
|
"@angular/localize": "16.2.1",
|
||||||
|
"@angular/platform-browser": "16.2.1",
|
||||||
|
"@angular/platform-browser-dynamic": "16.2.1",
|
||||||
|
"@angular/router": "16.2.1",
|
||||||
|
"@fullcalendar/angular": "6.1.8",
|
||||||
|
"@fullcalendar/core": "6.1.8",
|
||||||
|
"@fullcalendar/daygrid": "6.1.8",
|
||||||
|
"@fullcalendar/interaction": "6.1.8",
|
||||||
|
"@fullcalendar/timegrid": "6.1.8",
|
||||||
|
"@ng-bootstrap/ng-bootstrap": "15.1.1",
|
||||||
|
"bootstrap": "5.3.1",
|
||||||
|
"jquery": "3.7.0",
|
||||||
|
"primeicons": "6.0.1",
|
||||||
|
"primeng": "16.2.0",
|
||||||
|
"rxjs": "7.8.1",
|
||||||
|
"tslib": "2.6.2",
|
||||||
|
"zone.js": "0.13.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@angular-devkit/build-angular": "16.2.0",
|
||||||
|
"@angular/cli": "16.2.0",
|
||||||
|
"@angular/compiler-cli": "16.2.1",
|
||||||
|
"@types/jasmine": "4.3.5",
|
||||||
|
"@types/jasminewd2": "2.0.10",
|
||||||
|
"@types/node": "20.5.1",
|
||||||
|
"codelyzer": "6.0.2",
|
||||||
|
"jasmine-core": "5.1.0",
|
||||||
|
"jasmine-spec-reporter": "7.0.0",
|
||||||
|
"karma": "6.4.2",
|
||||||
|
"karma-chrome-launcher": "3.2.0",
|
||||||
|
"karma-coverage-istanbul-reporter": "3.0.3",
|
||||||
|
"karma-jasmine": "5.1.0",
|
||||||
|
"karma-jasmine-html-reporter": "2.1.0",
|
||||||
|
"protractor": "7.0.0",
|
||||||
|
"ts-node": "10.9.1",
|
||||||
|
"tslint": "6.1.0",
|
||||||
|
"typescript": "5.1.6"
|
||||||
|
}
|
||||||
|
}
|
||||||
8
ansible/files/doodlestudent/front/proxy.conf.json
Normal file
8
ansible/files/doodlestudent/front/proxy.conf.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"/api/*": {
|
||||||
|
"target": "http://localhost:8080",
|
||||||
|
"secure": false,
|
||||||
|
"logLevel": "debug",
|
||||||
|
"changeOrigin": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
.Poll_Informations {
|
||||||
|
background-color: white;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 1rem;
|
||||||
|
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.10);
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Meal_Preferences {
|
||||||
|
padding: 1rem;
|
||||||
|
border-bottom: 2px solid #F0F4F8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_Has_Meal {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_Has_Meal {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_Description_Title {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: #243B53;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_Infos {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_Info {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
<div class="Container">
|
||||||
|
|
||||||
|
|
||||||
|
<img src="../../assets/flat_logo.png" alt="Logo Simba" height="50px" [ngStyle]="{ 'marginBottom': '1rem' }" />
|
||||||
|
|
||||||
|
<!-- { isModalOpened &&
|
||||||
|
<div className="modal" onClick={() => setIsModalOpened(false)}>
|
||||||
|
<div className="Export_Modal" >
|
||||||
|
<a className="Export Disabled" target="_blank" rel="noopener noreferrer">
|
||||||
|
<svg aria-hidden="true" width="40px" height="40px" focusable="false" data-prefix="fas" data-icon="file-pdf" className="Export_Icon" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path fill="currentColor" d="M181.9 256.1c-5-16-4.9-46.9-2-46.9 8.4 0 7.6 36.9 2 46.9zm-1.7 47.2c-7.7 20.2-17.3 43.3-28.4 62.7 18.3-7 39-17.2 62.9-21.9-12.7-9.6-24.9-23.4-34.5-40.8zM86.1 428.1c0 .8 13.2-5.4 34.9-40.2-6.7 6.3-29.1 24.5-34.9 40.2zM248 160h136v328c0 13.3-10.7 24-24 24H24c-13.3 0-24-10.7-24-24V24C0 10.7 10.7 0 24 0h200v136c0 13.2 10.8 24 24 24zm-8 171.8c-20-12.2-33.3-29-42.7-53.8 4.5-18.5 11.6-46.6 6.2-64.2-4.7-29.4-42.4-26.5-47.8-6.8-5 18.3-.4 44.1 8.1 77-11.6 27.6-28.7 64.6-40.8 85.8-.1 0-.1.1-.2.1-27.1 13.9-73.6 44.5-54.5 68 5.6 6.9 16 10 21.5 10 17.9 0 35.7-18 61.1-61.8 25.8-8.5 54.1-19.1 79-23.2 21.7 11.8 47.1 19.5 64 19.5 29.2 0 31.2-32 19.7-43.4-13.9-13.6-54.3-9.7-73.6-7.2zM377 105L279 7c-4.5-4.5-10.6-7-17-7h-6v128h128v-6.1c0-6.3-2.5-12.4-7-16.9zm-74.1 255.3c4.1-2.7-2.5-11.9-42.8-9 37.1 15.8 42.8 9 42.8 9z"></path></svg>
|
||||||
|
<span>PDF (Premium)</span>
|
||||||
|
</a>
|
||||||
|
<a className="Export" target="_blank" rel="noopener noreferrer" href={`${BASE_URL}/polls/${slug}/results`}>
|
||||||
|
<svg aria-hidden="true" width="40px" height="40px" focusable="false" data-prefix="fas" data-icon="file-excel" className="Export_Icon" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path fill="currentColor" d="M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm60.1 106.5L224 336l60.1 93.5c5.1 8-.6 18.5-10.1 18.5h-34.9c-4.4 0-8.5-2.4-10.6-6.3C208.9 405.5 192 373 192 373c-6.4 14.8-10 20-36.6 68.8-2.1 3.9-6.1 6.3-10.5 6.3H110c-9.5 0-15.2-10.5-10.1-18.5l60.3-93.5-60.3-93.5c-5.2-8 .6-18.5 10.1-18.5h34.8c4.4 0 8.5 2.4 10.6 6.3 26.1 48.8 20 33.6 36.6 68.5 0 0 6.1-11.7 36.6-68.5 2.1-3.9 6.2-6.3 10.6-6.3H274c9.5-.1 15.2 10.4 10.1 18.4zM384 121.9v6.1H256V0h6.1c6.4 0 12.5 2.5 17 7l97.9 98c4.5 4.5 7 10.6 7 16.9z"></path></svg>
|
||||||
|
<span>EXCEL</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}-->
|
||||||
|
|
||||||
|
<app-top-bar [adminSlug]="poll?.slugAdmin" [slug]="poll?.slug" [padURL]="poll?.padURL" [talkToURL]="poll?.tlkURL" ></app-top-bar>
|
||||||
|
|
||||||
|
<p-card>
|
||||||
|
<p-toast></p-toast>
|
||||||
|
<ng-template pTemplate="title">
|
||||||
|
<h1>{{poll?.title}}</h1>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="subtitle">
|
||||||
|
<div class="Dates"><span>Créé il y a {{poll?.createdAt | dateago}}</span></div>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="content">
|
||||||
|
<div class="Poll_Infos">
|
||||||
|
<p class="Poll_Location"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"
|
||||||
|
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
class="feather feather-map-pin">
|
||||||
|
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path>
|
||||||
|
<circle cx="12" cy="10" r="3"></circle>
|
||||||
|
</svg>{{poll?.location}}</p>
|
||||||
|
<div *ngIf="poll?.has_meal" class="Poll_Has_Meal"><svg class="feather" aria-hidden="true" width="20" height="20"
|
||||||
|
focusable="false" data-prefix="fas" data-icon="utensils" role="img" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 416 512">
|
||||||
|
<path fill="currentColor"
|
||||||
|
d="M207.9 15.2c.8 4.7 16.1 94.5 16.1 128.8 0 52.3-27.8 89.6-68.9 104.6L168 486.7c.7 13.7-10.2 25.3-24 25.3H80c-13.7 0-24.7-11.5-24-25.3l12.9-238.1C27.7 233.6 0 196.2 0 144 0 109.6 15.3 19.9 16.1 15.2 19.3-5.1 61.4-5.4 64 16.3v141.2c1.3 3.4 15.1 3.2 16 0 1.4-25.3 7.9-139.2 8-141.8 3.3-20.8 44.7-20.8 47.9 0 .2 2.7 6.6 116.5 8 141.8.9 3.2 14.8 3.4 16 0V16.3c2.6-21.6 44.8-21.4 48-1.1zm119.2 285.7l-15 185.1c-1.2 14 9.9 26 23.9 26h56c13.3 0 24-10.7 24-24V24c0-13.2-10.7-24-24-24-82.5 0-221.4 178.5-64.9 300.9z">
|
||||||
|
</path>
|
||||||
|
</svg>
|
||||||
|
Cet évènement contient un repas
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div >
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="table-responsive-sm card">
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th rowspan="2"></th>
|
||||||
|
<th *ngFor="let ev of events" class="text-light" style="text-align: center;background-color: #545B62">{{ev.start | date:'EEEE d LLLL': 'CEST':'fr'}}</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th *ngFor="let ev of events" style="text-align: center">{{ev.start | date:'H:mm'}} <BR>-<BR> {{ev.end | date:'H:mm'}}</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><span>{{uniqueUsers.length}} participant</span><span *ngIf="uniqueUsers.length > 1">s</span></th>
|
||||||
|
<th *ngFor="let pc of poll?.pollChoices" style="text-align: center">{{pc.users.length}}</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let u of userChoices | keyvalue">
|
||||||
|
<td><input type="text" [disabled]='true' pInputText [ngModel]="uniqueUsers | usernamePipe:u.key"></td>
|
||||||
|
<td *ngFor="let ev of events" style="text-align: center"><p-checkbox [disabled]='true' [binary]="true" [ngModel]="u.value | selecteddate4userPipe:u.key:ev" ></p-checkbox></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td *ngFor="let ev of events" style="text-align: center"><p-button [disabled]="poll?.clos" (onClick)="selectEvent($event,ev )" >sélectionner cette date</p-button></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="footer">
|
||||||
|
|
||||||
|
<app-show-comments *ngIf="poll" [comments]="comments"></app-show-comments>
|
||||||
|
|
||||||
|
</ng-template>
|
||||||
|
</p-card>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AdminPollComponent } from './admin-poll.component';
|
||||||
|
|
||||||
|
describe('AdminPollComponent', () => {
|
||||||
|
let component: AdminPollComponent;
|
||||||
|
let fixture: ComponentFixture<AdminPollComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ AdminPollComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(AdminPollComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
|
import { MessageService } from 'primeng/api';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { PollService } from '../poll-service.service';
|
||||||
|
import { Poll, User, PollChoice, PollCommentElement, ChoiceUser } from '../model/model';
|
||||||
|
import { CalendarOptions, EventInput } from '@fullcalendar/core';
|
||||||
|
import { FullCalendarComponent } from '@fullcalendar/angular';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-admin-poll',
|
||||||
|
templateUrl: './admin-poll.component.html',
|
||||||
|
styleUrls: ['./admin-poll.component.css'],
|
||||||
|
providers: [MessageService, PollService, FullCalendarComponent]
|
||||||
|
|
||||||
|
})
|
||||||
|
export class AdminPollComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor(public messageService: MessageService, private actRoute: ActivatedRoute, private pollService: PollService) { }
|
||||||
|
slugid: string;
|
||||||
|
poll: Poll;
|
||||||
|
events: EventInput[] = [];
|
||||||
|
uniqueUsers: User[] = [];
|
||||||
|
userChoices: Map<number, PollChoice[]> = new Map();
|
||||||
|
comments: PollCommentElement[];
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.actRoute.paramMap.subscribe(params => {
|
||||||
|
this.slugid = params.get('slugadminid');
|
||||||
|
this.pollService.getPollBySlugAdminId(this.slugid).subscribe(p => {
|
||||||
|
this.poll = p;
|
||||||
|
if (p != null){
|
||||||
|
this.pollService.getComentsBySlugId(this.poll?.slug).subscribe(cs => this.comments = cs);
|
||||||
|
}
|
||||||
|
this.uniqueUsers.splice(0, this.uniqueUsers.length);
|
||||||
|
this.poll.pollChoices.forEach(pc => {
|
||||||
|
pc.users.forEach(user => {
|
||||||
|
if (this.uniqueUsers.filter(us => us.id === user.id).length === 0 ){
|
||||||
|
this.uniqueUsers.push(user);
|
||||||
|
this.userChoices.set(user.id, []);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const evt =
|
||||||
|
{
|
||||||
|
title: '',
|
||||||
|
start: pc.startDate,
|
||||||
|
end: pc.endDate,
|
||||||
|
resourceEditable: false,
|
||||||
|
eventResizableFromStart: false,
|
||||||
|
backgroundColor: 'red',
|
||||||
|
extendedProps: {
|
||||||
|
choiceid: pc.id,
|
||||||
|
selected: false
|
||||||
|
},
|
||||||
|
};
|
||||||
|
this.events.push(evt);
|
||||||
|
});
|
||||||
|
this.poll.pollChoices.forEach(pc => {
|
||||||
|
pc.users.forEach(us => {
|
||||||
|
this.userChoices.get(us.id).push(pc);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
selectEvent($event: any, event: EventInput): void{
|
||||||
|
this.pollService.selectEvent(event.extendedProps.choiceid).subscribe(e => {
|
||||||
|
this.messageService.add({
|
||||||
|
severity: 'success',
|
||||||
|
summary: 'Données enregistrées',
|
||||||
|
detail: 'Le sondage est maintenant close'}
|
||||||
|
);
|
||||||
|
this.poll.clos = true;
|
||||||
|
}, (error) => {
|
||||||
|
this.messageService.add(
|
||||||
|
{
|
||||||
|
severity: 'warn',
|
||||||
|
summary: 'Sélection de cette date impossible',
|
||||||
|
detail: 'Le sondage n\'a pu être clos'}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,488 @@
|
|||||||
|
:root {
|
||||||
|
--header-height : 180px;
|
||||||
|
--participant-width : 230px;
|
||||||
|
--cell-width : 65px;
|
||||||
|
--cell-height: 40px;
|
||||||
|
--new-participant-height : 65px;
|
||||||
|
--cell-padding : 1rem;
|
||||||
|
|
||||||
|
--color-new-participant : #E6E6FF;
|
||||||
|
--color-vote-yes : #E6E6FF;
|
||||||
|
--color-vote-no :rgb(254,246,246) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul{
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.Poll_Has_Meal {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_Vote_Wrapper{
|
||||||
|
display: flex;
|
||||||
|
justify-content:center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_Vote_Content{
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
/*border : 2px solid black; */
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 390px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Cell_Poll_Header{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Cell_Option .Cell_Poll_Header, .Cell_Option_Votes{
|
||||||
|
border-left: 1px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.Cell_Options{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
.Cell_Option{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Tailles de cellules*/
|
||||||
|
.Cell_Participants_Header,.Cell_Participant_Count,
|
||||||
|
.Cell_New_Participant,.Cell_Participant{
|
||||||
|
width: var(--participant-width);
|
||||||
|
}
|
||||||
|
.Cell_Option_Name,.Cell_Option_Count,
|
||||||
|
.Cell_Option_New_Participant_Vote,.Cell_Option_Vote_Yes,
|
||||||
|
.Cell_Option_Vote_No{
|
||||||
|
width: var(--cell-width);
|
||||||
|
}
|
||||||
|
/*.Cell_New_Participant,.Cell_Option_New_Participant_Vote{
|
||||||
|
height: var(--new-participant-height);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
.Cell_Option_New_Participant_Vote {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Checkbox_Btn.LastCheck {
|
||||||
|
border-radius: 0 0 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.Cell_Participants_Header,.Cell_Option_Name, .Cell_Header_Name{
|
||||||
|
height: var(--header-height);
|
||||||
|
}
|
||||||
|
/*.Cell_Participant_Count,.Cell_Option_Count,
|
||||||
|
.Cell_Option_Vote_Yes,.Cell_Option_Vote_No,.Cell_Participant{
|
||||||
|
height: var(--cell-height);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
.Cell_Participant_Count {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Disposition dans les cellules */
|
||||||
|
.Cell_Participants_Header,.Cell_Participant_Count,
|
||||||
|
.Cell_Option_Count,
|
||||||
|
.Cell_Option_Vote_Yes,.Cell_Option_Vote_No{
|
||||||
|
padding: var(--cell-padding);
|
||||||
|
text-align: center;
|
||||||
|
justify-content: center;
|
||||||
|
/*border: 1px solid black;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_Vote_Content {
|
||||||
|
border: 1px solid #E6E6FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*.Cell_Participant,.Cell_New_Participant{
|
||||||
|
padding: var(--cell-padding);
|
||||||
|
padding-left: 20%;
|
||||||
|
border: 1px solid black;
|
||||||
|
text-align: left;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
.Cell_Option_Name, .Cell_Participants_Header {
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.Cell_Participant, .Cell_Vote {
|
||||||
|
height: 50px;
|
||||||
|
padding: 1rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*Couleurs*/
|
||||||
|
.Cell_Option_New_Participant_Vote{
|
||||||
|
background-color: var(--color-new-participant);
|
||||||
|
}
|
||||||
|
.Cell_Option_Vote_Yes{
|
||||||
|
background-color: var(--color-vote-yes)
|
||||||
|
}
|
||||||
|
.Cell_Option_Vote_No{
|
||||||
|
background-color: var(--color-vote-no)
|
||||||
|
}
|
||||||
|
/* Fixe la premiere colonne et parametrage du scroll*/
|
||||||
|
|
||||||
|
.Cell_Options{
|
||||||
|
overflow-x: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.Cell_New_Participant_Input {
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 0;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Cell_New_Participant_Input.error {
|
||||||
|
border: 2px solid #EF4E4E;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_View_Btn {
|
||||||
|
display: flex;
|
||||||
|
flex: 1 1;
|
||||||
|
border: 1px solid #1D0EBE;
|
||||||
|
display: flex;
|
||||||
|
color: #4D3DF7;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 0.5rem 1.2rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_View_Btn:first-child {
|
||||||
|
border-radius: 5px 0 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_View_Btn:last-child {
|
||||||
|
border-radius: 0 5px 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_View_Btn.active {
|
||||||
|
background-color: #4D3DF7;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_Btns {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Meal_Preferences_Toggle {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 1rem;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_Location {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feather {
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Cell_Header {
|
||||||
|
width: var(--participant-width);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_Has_Meal {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_Description_Title {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: #243B53;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_Infos {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_Info {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.green {
|
||||||
|
background-color: #199473;
|
||||||
|
}
|
||||||
|
|
||||||
|
.green:hover {
|
||||||
|
background-color: #147D64;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_Vote_Action {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.Cell_Poll_Header.Cell_Option_Name {
|
||||||
|
width: 100%!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
background-color: #65D6AD;
|
||||||
|
color: #014D40;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_Subtitle {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
font-size: 1rem;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Dates {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Pad_Url {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Edit_Link {
|
||||||
|
margin-left: 1rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #4d3cf7;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Edit_Link:hover {
|
||||||
|
color: #1D0EBE;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Link {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #4d3cf7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Link:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Cell_Day {
|
||||||
|
background-color: #4d3cf7;
|
||||||
|
color: white;
|
||||||
|
padding: 1rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_Start_Date {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_Date {
|
||||||
|
text-align: center;
|
||||||
|
padding: 8px;
|
||||||
|
color: #4d3cf7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Checkbox_Btn {
|
||||||
|
width: 65px;
|
||||||
|
height: 50px;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
text-align: center;
|
||||||
|
transition: background-color 0.3s linear;
|
||||||
|
border: 1px solid #4d3cf7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Checkbox_Btn.Active {
|
||||||
|
background-color: #4d3cf7;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Cell_New_Participant {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.Links {
|
||||||
|
display: flex;
|
||||||
|
font-weight: 600;
|
||||||
|
width: 100%;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
background-color: #4D3DF7;
|
||||||
|
border-radius: 5px 5px 0 0;
|
||||||
|
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.10);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.Links_Right {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Links_Left {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Feat_Link {
|
||||||
|
padding: 0.7rem 1rem;
|
||||||
|
text-decoration: none;
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
transition: all 0.3s linear;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Feat_Link:last-child {
|
||||||
|
border-radius: 0 5px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Feat_Link.Unique {
|
||||||
|
border-radius: 5px 5px 0 0!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Feat_Link:hover {
|
||||||
|
background-color: #0C008C;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MealPref {
|
||||||
|
padding: 1rem 0;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Author_MealPref {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #4d3cf7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Author_Comment {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #4d3cf7;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.orange {
|
||||||
|
background-color: #F7D070;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orange:hover {
|
||||||
|
background-color: #E9B949;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
position: fixed; /* Stay in place */
|
||||||
|
z-index: 1; /* Sit on top */
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%; /* Full width */
|
||||||
|
height: 100%; /* Full height */
|
||||||
|
overflow: auto; /* Enable scroll if needed */
|
||||||
|
background-color: rgb(0,0,0); /* Fallback color */
|
||||||
|
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
|
||||||
|
}
|
||||||
|
|
||||||
|
.Export_Modal {
|
||||||
|
background-color: #fefefe;
|
||||||
|
margin: 15% auto; /* 15% from the top and centered */
|
||||||
|
width: 500px; /* Could be more or less, depending on screen size */
|
||||||
|
z-index: 2;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 160px;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.10);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Export {
|
||||||
|
padding: 20px;
|
||||||
|
height: 100%;
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
color: #4d3cf7;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: bold;
|
||||||
|
transition: background-color 0.3s linear;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Export:hover {
|
||||||
|
background-color: #4d3cf7;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Export:first-child {
|
||||||
|
border-right: 4px solid #4d3cf7;
|
||||||
|
border-radius: 3px 0 0 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Export:last-child {
|
||||||
|
border-radius: 0 3px 3px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Export_Icon {
|
||||||
|
margin: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_Informations {
|
||||||
|
background-color: white;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 1rem;
|
||||||
|
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.10);
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Meal_Preferences {
|
||||||
|
padding: 1rem;
|
||||||
|
border-bottom: 2px solid #F0F4F8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Disabled {
|
||||||
|
background-color: #cccccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Disabled:hover {
|
||||||
|
color: #4d3cf7;
|
||||||
|
background-color: #cccccc;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Comment {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
<div class="Container">
|
||||||
|
<img src="../../assets/flat_logo.png" alt="Logo Simba" height="50px" [ngStyle]="{ 'marginBottom': '1rem' }" />
|
||||||
|
<app-top-bar [slug]="poll?.slug" [padURL]="poll?.padURL" [talkToURL]="poll?.tlkURL" ></app-top-bar>
|
||||||
|
|
||||||
|
|
||||||
|
<p-card>
|
||||||
|
<p-toast></p-toast>
|
||||||
|
<ng-template pTemplate="title">
|
||||||
|
<h1>{{poll?.title}}</h1>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="subtitle">
|
||||||
|
<div class="Dates"><span>Créé il y a {{poll?.createdAt | dateago}}</span></div>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="content">
|
||||||
|
<div class="Poll_Infos">
|
||||||
|
<p class="Poll_Location"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"
|
||||||
|
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
class="feather feather-map-pin">
|
||||||
|
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path>
|
||||||
|
<circle cx="12" cy="10" r="3"></circle>
|
||||||
|
</svg>{{poll?.location}}</p>
|
||||||
|
<div *ngIf="poll?.has_meal" class="Poll_Has_Meal"><svg class="feather" aria-hidden="true" width="20" height="20"
|
||||||
|
focusable="false" data-prefix="fas" data-icon="utensils" role="img" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 416 512">
|
||||||
|
<path fill="currentColor"
|
||||||
|
d="M207.9 15.2c.8 4.7 16.1 94.5 16.1 128.8 0 52.3-27.8 89.6-68.9 104.6L168 486.7c.7 13.7-10.2 25.3-24 25.3H80c-13.7 0-24.7-11.5-24-25.3l12.9-238.1C27.7 233.6 0 196.2 0 144 0 109.6 15.3 19.9 16.1 15.2 19.3-5.1 61.4-5.4 64 16.3v141.2c1.3 3.4 15.1 3.2 16 0 1.4-25.3 7.9-139.2 8-141.8 3.3-20.8 44.7-20.8 47.9 0 .2 2.7 6.6 116.5 8 141.8.9 3.2 14.8 3.4 16 0V16.3c2.6-21.6 44.8-21.4 48-1.1zm119.2 285.7l-15 185.1c-1.2 14 9.9 26 23.9 26h56c13.3 0 24-10.7 24-24V24c0-13.2-10.7-24-24-24-82.5 0-221.4 178.5-64.9 300.9z">
|
||||||
|
</path>
|
||||||
|
</svg>
|
||||||
|
Cet évènement contient un repas
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="p-fluid">
|
||||||
|
<div class="p-field">
|
||||||
|
<label for="nom">Nom prénom participant</label>
|
||||||
|
<input #nom="ngModel" id="nom" type="text" required pInputText [(ngModel)]="personalInformation.nom"
|
||||||
|
[ngClass]="{'p-invalid': (nom.invalid && submitted) || (nom.dirty && nom.invalid)}">
|
||||||
|
<small *ngIf="(nom.invalid && submitted) || (nom.dirty && nom.invalid)" class="p-error">Le nom est
|
||||||
|
requis.</small>
|
||||||
|
</div>
|
||||||
|
<div class="p-field">
|
||||||
|
<label for="mail">Email participant</label>
|
||||||
|
<span class="p-input-icon-right">
|
||||||
|
<i *ngIf="loademail" class="pi pi-spin pi-spinner" ></i>
|
||||||
|
|
||||||
|
<input #mail="ngModel" id="mail" type="email" required pInputText (change)="getUserFromMail()" [(ngModel)]="personalInformation.mail"
|
||||||
|
[ngClass]="{'p-invalid': (mail.invalid && submitted) || (mail.dirty && mail.invalid)}">
|
||||||
|
</span>
|
||||||
|
<small class="p-error" *ngIf="(mail.invalid && submitted )|| (mail.dirty && mail.invalid)">Le
|
||||||
|
mail est requis.</small>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="p-field">
|
||||||
|
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 1rem;font-weight: normal;">Avez vous un agenda avec un flux ics accessible ?</p>
|
||||||
|
<p-inputSwitch [(ngModel)]="hasics"></p-inputSwitch>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="hasics" class="p-field">
|
||||||
|
<label for="ics">URL ICS du participant</label>
|
||||||
|
<span class="p-input-icon-right">
|
||||||
|
<i *ngIf="loadics" class="pi pi-spin pi-spinner" ></i>
|
||||||
|
<input #mail="ngModel" id="ics" type="text" pInputText (change)="getICS()" [(ngModel)]="personalInformation.ics">
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="poll?.has_meal" class="p-field">
|
||||||
|
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 1rem;font-weight: normal;">Avez vous des préférences alimentaires ?</p>
|
||||||
|
<p-inputSwitch [(ngModel)]="personalInformation.pref"></p-inputSwitch>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="personalInformation?.pref" class="p-field">
|
||||||
|
<label for="desc">Description préférences alimentaires</label>
|
||||||
|
<textarea #desc="ngModel" id="desc" required pInputTextarea [(ngModel)]="personalInformation.desc"
|
||||||
|
[ngClass]="{'p-invalid': (desc.invalid && submitted) || (desc.dirty && desc.invalid)}"></textarea>
|
||||||
|
<small class="p-error" *ngIf="(desc.invalid && submitted) || (desc.dirty && desc.invalid)">La description est
|
||||||
|
requise.</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p-selectButton [options]="calendarortableoption" [(ngModel)]="calendarortable">
|
||||||
|
<ng-template let-item>
|
||||||
|
<i [class]="item.icon">Vue {{item.text}}</i>
|
||||||
|
</ng-template>
|
||||||
|
</p-selectButton>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="calendarortable ==='calendar'">
|
||||||
|
<full-calendar #calendar [options]="options"></full-calendar>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="calendarortable !='calendar'">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="table-responsive-sm card">
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th rowspan="2"></th>
|
||||||
|
<th *ngFor="let ev of events" class="text-light" style="text-align: center;background-color: #545B62">{{ev.start | date:'EEEE d LLLL': 'CEST':'fr'}}</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th *ngFor="let ev of events" style="text-align: center">{{ev.start | date:'H:mm'}} <BR>-<BR> {{ev.end | date:'H:mm'}}</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><span>{{uniqueUsers.length + 1}} participant</span><span *ngIf="uniqueUsers.length > 0">s</span></th>
|
||||||
|
<th *ngFor="let pc of poll?.pollChoices" style="text-align: center">{{pc.users.length}}</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let u of userChoices | keyvalue">
|
||||||
|
<td><input type="text" [disabled]='true' pInputText [ngModel]="uniqueUsers | usernamePipe:u.key"></td>
|
||||||
|
<td *ngFor="let ev of events" style="text-align: center"><p-checkbox [disabled]='true' [binary]="true" [ngModel]="u.value | selecteddate4userPipe:u.key:ev" ></p-checkbox></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><input #nomvotant="" id="nomvotant" type="text" required pInputText [(ngModel)]="personalInformation.nom"></td>
|
||||||
|
<td *ngFor="let ev of events" style="text-align: center"><p-checkbox [binary]="true" (onChange)="updateEvent($event,ev )" [ngModel]="ev.extendedProps.selected" ></p-checkbox></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p-button [disabled]="voeuxsoumis" label="Soumettre voeux" (onClick)="createReponse()"
|
||||||
|
icon="pi pi-angle-left"></p-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="footer">
|
||||||
|
<app-show-comments *ngIf="poll" [comments]="comments"></app-show-comments>
|
||||||
|
|
||||||
|
<div class="p-fluid">
|
||||||
|
<div class="p-field">
|
||||||
|
<label for="comment">Auteur du commentaire associé à ce sondage</label>
|
||||||
|
<input #comment="ngModel" id="comment" type="text" required pInputText [(ngModel)]="comment1"
|
||||||
|
[ngClass]="{'p-invalid': (comment.invalid && csubmitted) || (comment.dirty && comment.invalid)}">
|
||||||
|
<small *ngIf="(comment.invalid && csubmitted) || (comment.dirty && comment.invalid)" class="p-error">L'auteur
|
||||||
|
du commentaire est requis.</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="p-field">
|
||||||
|
<label for="commentdesc">Commentaire</label>
|
||||||
|
<textarea #commentdesc="ngModel" id="commentdesc" required pInputTextarea [(ngModel)]="commentdesc1"
|
||||||
|
[ngClass]="{'p-invalid': (commentdesc.invalid && csubmitted) || (commentdesc.dirty && commentdesc.invalid)}"></textarea>
|
||||||
|
<small class="p-error"
|
||||||
|
*ngIf="(commentdesc.invalid && csubmitted) || (commentdesc.dirty && commentdesc.invalid)">Le commentaire est
|
||||||
|
requis.</small>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p-button [disabled]="commentsoumis" label="Ajouter commentaire" (onClick)="createComment()"
|
||||||
|
icon="pi pi-angle-left"></p-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</ng-template>
|
||||||
|
</p-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--<p-button (onClick)="testEvent()">test</p-button>-->
|
||||||
|
<!-- Modal -->
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AnswerPollComponent } from './answer-poll.component';
|
||||||
|
|
||||||
|
describe('AnswerPollComponent', () => {
|
||||||
|
let component: AnswerPollComponent;
|
||||||
|
let fixture: ComponentFixture<AnswerPollComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ AnswerPollComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(AnswerPollComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,360 @@
|
|||||||
|
import { Component, OnInit, ViewChild, AfterViewChecked } from '@angular/core';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { PollService } from '../poll-service.service';
|
||||||
|
import { Poll, ChoiceUser, PollCommentElement, User, PollChoice } from '../model/model';
|
||||||
|
import { CalendarOptions, EventInput } from '@fullcalendar/core';
|
||||||
|
import { FullCalendarComponent } from '@fullcalendar/angular';
|
||||||
|
import frLocale from '@fullcalendar/core/locales/fr';
|
||||||
|
import { MessageService } from 'primeng/api';
|
||||||
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
import { ModalPollClosComponent } from '../modal-poll-clos/modal-poll-clos.component';
|
||||||
|
import dayGridPlugin from '@fullcalendar/daygrid';
|
||||||
|
import interactionPlugin from '@fullcalendar/interaction';
|
||||||
|
import timeGridPlugin from '@fullcalendar/timegrid';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-answer-poll',
|
||||||
|
templateUrl: './answer-poll.component.html',
|
||||||
|
styleUrls: ['./answer-poll.component.css'],
|
||||||
|
providers: [MessageService, PollService, FullCalendarComponent, NgbModal]
|
||||||
|
|
||||||
|
})
|
||||||
|
export class AnswerPollComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor(public messageService: MessageService,
|
||||||
|
// tslint:disable-next-line:align
|
||||||
|
private actRoute: ActivatedRoute, private pollService: PollService,
|
||||||
|
// tslint:disable-next-line:align
|
||||||
|
private modalService: NgbModal) { }
|
||||||
|
slugid: string;
|
||||||
|
poll: Poll;
|
||||||
|
calendarortableoption: any[];
|
||||||
|
calendarortable = 'calendar';
|
||||||
|
personalInformation: any = {
|
||||||
|
nom: '',
|
||||||
|
mail: '',
|
||||||
|
desc: '',
|
||||||
|
ics: '',
|
||||||
|
pref: false
|
||||||
|
};
|
||||||
|
hasics: false;
|
||||||
|
options: CalendarOptions;
|
||||||
|
@ViewChild('calendar') calendarComponent: FullCalendarComponent;
|
||||||
|
submitted = false;
|
||||||
|
csubmitted = false;
|
||||||
|
voeuxsoumis = false;
|
||||||
|
commentsoumis = false;
|
||||||
|
events: EventInput[] = [];
|
||||||
|
eventsfromics: EventInput[] = [];
|
||||||
|
allevents: EventInput[] = [];
|
||||||
|
loadics = false;
|
||||||
|
loademail = false;
|
||||||
|
comments: PollCommentElement[];
|
||||||
|
|
||||||
|
comment1 = '';
|
||||||
|
commentdesc1 = '';
|
||||||
|
uniqueUsers: User[] = [];
|
||||||
|
userChoices: Map<number, PollChoice[]> = new Map();
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.calendarortableoption = [
|
||||||
|
{ icon: 'pi pi-calendar', text: 'Calendrier', value: 'calendar' },
|
||||||
|
{ icon: 'pi pi-table', text: 'Tableau', value: 'table' },
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
this.actRoute.paramMap.subscribe(params => {
|
||||||
|
this.slugid = params.get('slugid');
|
||||||
|
this.pollService.getPollBySlugId(this.slugid).subscribe(p => {
|
||||||
|
this.poll = p;
|
||||||
|
this.pollService.getComentsBySlugId(this.slugid).subscribe(cs => this.comments = cs);
|
||||||
|
|
||||||
|
|
||||||
|
if (this.poll.clos) {
|
||||||
|
this.openModal();
|
||||||
|
}
|
||||||
|
const calendarApi = this.calendarComponent.getApi();
|
||||||
|
// calendarApi.next();
|
||||||
|
this.uniqueUsers.splice(0, this.uniqueUsers.length);
|
||||||
|
this.poll.pollChoices.forEach(pc => {
|
||||||
|
pc.users.forEach(user => {
|
||||||
|
if (this.uniqueUsers.filter(us => us.id === user.id).length === 0) {
|
||||||
|
this.uniqueUsers.push(user);
|
||||||
|
this.userChoices.set(user.id, []);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const evt =
|
||||||
|
{
|
||||||
|
title: '',
|
||||||
|
start: pc.startDate,
|
||||||
|
end: pc.endDate,
|
||||||
|
resourceEditable: false,
|
||||||
|
eventResizableFromStart: false,
|
||||||
|
backgroundColor: 'red',
|
||||||
|
id: this.getUniqueId(8),
|
||||||
|
extendedProps: {
|
||||||
|
choiceid: pc.id,
|
||||||
|
selected: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
calendarApi.addEvent(evt, true);
|
||||||
|
this.events.push(evt);
|
||||||
|
this.allevents.push(evt);
|
||||||
|
|
||||||
|
});
|
||||||
|
this.poll.pollChoices.forEach(pc => {
|
||||||
|
pc.users.forEach(us => {
|
||||||
|
this.userChoices.get(us.id).push(pc);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.options = {
|
||||||
|
initialView: 'timeGridWeek',
|
||||||
|
plugins: [dayGridPlugin, interactionPlugin, timeGridPlugin],
|
||||||
|
|
||||||
|
// dateClick: this.handleDateClick.bind(this), // bind is important!
|
||||||
|
/*eventDragStart: (timeSheetEntry, jsEvent, ui, activeView) => {
|
||||||
|
this.eventDragStart(
|
||||||
|
timeSheetEntry, jsEvent, ui, activeView
|
||||||
|
);
|
||||||
|
},
|
||||||
|
eventDragStop: (timeSheetEntry, jsEvent, ui, activeView) => {
|
||||||
|
this.eventDragStop(
|
||||||
|
timeSheetEntry, jsEvent, ui, activeView
|
||||||
|
);
|
||||||
|
},*/
|
||||||
|
// events: this.events,
|
||||||
|
events: this.allevents,
|
||||||
|
editable: false,
|
||||||
|
droppable: false,
|
||||||
|
// selectMirror: true,
|
||||||
|
eventResizableFromStart: false,
|
||||||
|
selectable: false,
|
||||||
|
locale: frLocale,
|
||||||
|
themeSystem: 'bootstrap',
|
||||||
|
slotMinTime: '08:00:00',
|
||||||
|
slotMaxTime: '20:00:00',
|
||||||
|
eventMouseEnter: (mouseEnterInfo) => {
|
||||||
|
|
||||||
|
},
|
||||||
|
eventClick: (info) => {
|
||||||
|
if (!info.event.extendedProps.fromics) {
|
||||||
|
if (info.event.extendedProps.selected) {
|
||||||
|
info.event.setExtendedProp('selected', false);
|
||||||
|
const evt = this.events.filter(e => e.extendedProps.choiceid === info.event.extendedProps.choiceid).pop();
|
||||||
|
evt.extendedProps.selected = false;
|
||||||
|
evt.backgroundColor = 'red';
|
||||||
|
info.event.setProp('backgroundColor', 'red');
|
||||||
|
this.poll.pollChoices.filter(pc => pc.id === evt.extendedProps.choiceid)[0].users.splice(-1, 1);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
info.event.setExtendedProp('selected', true);
|
||||||
|
const evt = this.events.filter(e => e.extendedProps.choiceid === info.event.extendedProps.choiceid).pop();
|
||||||
|
evt.extendedProps.selected = true;
|
||||||
|
evt.backgroundColor = 'green';
|
||||||
|
info.event.setProp('backgroundColor', 'green');
|
||||||
|
this.poll.pollChoices.filter(pc => pc.id === evt.extendedProps.choiceid)[0].users.push({ id: -1 });
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// info.event.remove();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
updateEvent($event: any, event: EventInput): void {
|
||||||
|
|
||||||
|
event.extendedProps.selected = $event.checked;
|
||||||
|
if ($event.checked) {
|
||||||
|
event.backgroundColor = 'green';
|
||||||
|
this.poll.pollChoices.filter(pc => pc.id === event.extendedProps.choiceid)[0].users.push({ id: -1 });
|
||||||
|
|
||||||
|
} else {
|
||||||
|
event.backgroundColor = 'red';
|
||||||
|
this.poll.pollChoices.filter(pc => pc.id === event.extendedProps.choiceid)[0].users.splice(-1, 1);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createComment(): void {
|
||||||
|
|
||||||
|
|
||||||
|
if (this.comment1 && this.commentdesc1) {
|
||||||
|
const c: PollCommentElement = {
|
||||||
|
content: this.commentdesc1,
|
||||||
|
auteur: this.comment1
|
||||||
|
};
|
||||||
|
this.pollService.addComment4Poll(this.slugid, c).subscribe(e => {
|
||||||
|
this.messageService.add({
|
||||||
|
severity: 'success',
|
||||||
|
summary: 'Données enregistrées',
|
||||||
|
detail: 'Merci pour ce commentaire'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.pollService.getComentsBySlugId(this.poll?.slug).subscribe(cs => this.comments = cs);
|
||||||
|
this.commentsoumis = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.messageService.add(
|
||||||
|
{
|
||||||
|
severity: 'warn',
|
||||||
|
summary: 'Données incomplètes',
|
||||||
|
detail: 'Veuillez remplir les champs requis'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.csubmitted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
createReponse(): void {
|
||||||
|
if (this.personalInformation.nom && this.personalInformation.mail &&
|
||||||
|
this.events.filter(e => e.extendedProps.selected).length > 0 &&
|
||||||
|
(this.personalInformation.desc || !this.personalInformation.pref)) {
|
||||||
|
const cu: ChoiceUser = {
|
||||||
|
username: this.personalInformation.nom,
|
||||||
|
mail: this.personalInformation.mail,
|
||||||
|
pref: this.personalInformation.desc,
|
||||||
|
ics: this.personalInformation.ics,
|
||||||
|
choices: this.events.filter(e => e.extendedProps.selected).map(x => x.extendedProps.choiceid)
|
||||||
|
};
|
||||||
|
this.pollService.updateChoice4user(cu).subscribe(e => {
|
||||||
|
// cu.choices.forEach(c => this.poll.pollChoices.filter( c1 => c1.id === c)[0].users.push(e));
|
||||||
|
// if (this.uniqueUsers.filter(u1 => u1.id === e.id ).length === 0) {
|
||||||
|
// this.uniqueUsers.push(e);
|
||||||
|
// }
|
||||||
|
this.messageService.add({
|
||||||
|
severity: 'success',
|
||||||
|
summary: 'Données enregistrées',
|
||||||
|
detail: 'Merci pour votre participation'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.voeuxsoumis = true;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.messageService.add(
|
||||||
|
{
|
||||||
|
severity: 'warn',
|
||||||
|
summary: 'Données incomplètes',
|
||||||
|
detail: 'Veuillez remplir les champs requis et sélectioner au moins une date'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.submitted = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
getICS(): void {
|
||||||
|
this.loadics = true;
|
||||||
|
this.pollService.getICS(this.slugid, this.personalInformation.ics).subscribe(res => {
|
||||||
|
this.loadics = false;
|
||||||
|
|
||||||
|
const calendarApi = this.calendarComponent.getApi();
|
||||||
|
if (res.eventdtos.length > 0) {
|
||||||
|
this.eventsfromics.forEach(eid => {
|
||||||
|
const index = this.allevents.indexOf(eid);
|
||||||
|
if (index > -1) {
|
||||||
|
this.allevents.splice(index, 1);
|
||||||
|
}
|
||||||
|
calendarApi.getEventById(eid.id)?.remove();
|
||||||
|
});
|
||||||
|
this.eventsfromics = [];
|
||||||
|
}
|
||||||
|
console.log(res);
|
||||||
|
|
||||||
|
res.eventdtos.forEach(evtdto => { // calendarApi.next();
|
||||||
|
const evt1 =
|
||||||
|
{
|
||||||
|
title: evtdto.description,
|
||||||
|
start: evtdto.startDate,
|
||||||
|
end: evtdto.endDate,
|
||||||
|
resourceEditable: false,
|
||||||
|
eventResizableFromStart: false,
|
||||||
|
id: this.getUniqueId(8),
|
||||||
|
|
||||||
|
backgroundColor: 'blue',
|
||||||
|
extendedProps: {
|
||||||
|
fromics: true
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
const eventAPI = calendarApi.addEvent(evt1, true);
|
||||||
|
this.eventsfromics.push(evt1);
|
||||||
|
this.allevents.push(evt1);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
const unselected = this.events.map(ev => ev.extendedProps.choiceid);
|
||||||
|
res.selectedChoices.forEach(e => {
|
||||||
|
const index = unselected.indexOf(e);
|
||||||
|
if (index > -1) {
|
||||||
|
unselected.splice(index, 1);
|
||||||
|
}
|
||||||
|
const evt1 = this.events.filter(ev => ev.extendedProps.choiceid === e)[0];
|
||||||
|
|
||||||
|
const evt2 = calendarApi.getEventById(evt1.id);
|
||||||
|
evt1.backgroundColor = 'red';
|
||||||
|
evt1.extendedProps.selected = false;
|
||||||
|
evt2.setProp('backgroundColor', 'red');
|
||||||
|
// this.poll.pollChoices.filter(pc => pc.id === evt1.extendedProps.choiceid)[0].users.push({ id: -1 });
|
||||||
|
});
|
||||||
|
unselected.forEach(e => {
|
||||||
|
const evt1 = this.events.filter(ev => ev.extendedProps.choiceid === e)[0];
|
||||||
|
|
||||||
|
const evt2 = calendarApi.getEventById(evt1.id);
|
||||||
|
evt1.backgroundColor = 'green';
|
||||||
|
evt1.extendedProps.selected = true;
|
||||||
|
evt2.setProp('backgroundColor', 'green');
|
||||||
|
this.poll.pollChoices.filter(pc => pc.id === evt1.extendedProps.choiceid)[0].users.push({ id: -1 });
|
||||||
|
});
|
||||||
|
}, (err) => {
|
||||||
|
this.loadics = false;
|
||||||
|
|
||||||
|
this.messageService.add(
|
||||||
|
{
|
||||||
|
severity: 'warn',
|
||||||
|
summary: 'Ne peut récupérer l\'agenda à partir de l\'adresse de l\'ics',
|
||||||
|
detail: 'Une erreur s\'est produite au moment de la récupération de l\'agenda'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
openModal(): void {
|
||||||
|
const modalRef = this.modalService.open(ModalPollClosComponent, {
|
||||||
|
beforeDismiss: () => false,
|
||||||
|
centered: true,
|
||||||
|
windowClass: 'lgModal',
|
||||||
|
backdrop: 'static'
|
||||||
|
});
|
||||||
|
modalRef.componentInstance.poll = this.poll;
|
||||||
|
}
|
||||||
|
|
||||||
|
getUserFromMail(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
private getUniqueId(parts: number): string {
|
||||||
|
const stringArr = [];
|
||||||
|
for (let i = 0; i < parts; i++) {
|
||||||
|
// tslint:disable-next-line:no-bitwise
|
||||||
|
const S4 = (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
|
||||||
|
stringArr.push(S4);
|
||||||
|
}
|
||||||
|
return stringArr.join('-');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { Routes, RouterModule } from '@angular/router';
|
||||||
|
import { HomeComponentComponent } from './home-component/home-component.component';
|
||||||
|
import { CreatePollComponentComponent } from './create-poll-component/create-poll-component.component';
|
||||||
|
import { AnswerPollComponent } from './answer-poll/answer-poll.component';
|
||||||
|
import { AdminPollComponent } from './admin-poll/admin-poll.component';
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: HomeComponentComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'create',
|
||||||
|
component: CreatePollComponentComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'update/:slugadminid',
|
||||||
|
component: CreatePollComponentComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'answer/:slugid',
|
||||||
|
component: AnswerPollComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'admin/:slugadminid',
|
||||||
|
component: AdminPollComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forRoot(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class AppRoutingModule { }
|
||||||
87
ansible/files/doodlestudent/front/src/app/app.component.css
Normal file
87
ansible/files/doodlestudent/front/src/app/app.component.css
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
.Container {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 2rem auto;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SmallCard_Container {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SmallCard {
|
||||||
|
background-color: white;
|
||||||
|
margin-right: 1rem;
|
||||||
|
padding: 2rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SmallCard_Image {
|
||||||
|
padding: 1rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SmallCard_Title {
|
||||||
|
padding: 1rem;
|
||||||
|
font-weight: 800;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SmallCard_Subtitle {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SmallCard:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Home_Container {
|
||||||
|
width: 1024px;
|
||||||
|
margin: 0 auto;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Home_Wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Home_Logo {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Home_Button {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Home_CreateLink {
|
||||||
|
padding: 1rem;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #43dbac;
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 1.3rem;
|
||||||
|
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.10);
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<router-outlet></router-outlet>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
|
||||||
|
describe('AppComponent', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [
|
||||||
|
RouterTestingModule
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
AppComponent
|
||||||
|
],
|
||||||
|
}).compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create the app', () => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
const app = fixture.componentInstance;
|
||||||
|
expect(app).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should have as title 'tlcfront'`, () => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
const app = fixture.componentInstance;
|
||||||
|
expect(app.title).toEqual('tlcfront');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render title', () => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
fixture.detectChanges();
|
||||||
|
const compiled = fixture.nativeElement;
|
||||||
|
expect(compiled.querySelector('.content span').textContent).toContain('tlcfront app is running!');
|
||||||
|
});
|
||||||
|
});
|
||||||
12
ansible/files/doodlestudent/front/src/app/app.component.ts
Normal file
12
ansible/files/doodlestudent/front/src/app/app.component.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { HomeComponentComponent } from './home-component/home-component.component';
|
||||||
|
import { CreatePollComponentComponent } from './create-poll-component/create-poll-component.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-root',
|
||||||
|
templateUrl: './app.component.html',
|
||||||
|
styleUrls: ['./app.component.css'],
|
||||||
|
providers: [HomeComponentComponent, CreatePollComponentComponent]
|
||||||
|
})
|
||||||
|
export class AppComponent {
|
||||||
|
}
|
||||||
86
ansible/files/doodlestudent/front/src/app/app.module.ts
Normal file
86
ansible/files/doodlestudent/front/src/app/app.module.ts
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
import { CardSmallComponentComponent } from './card-small-component/card-small-component.component';
|
||||||
|
import { HomeComponentComponent } from './home-component/home-component.component';
|
||||||
|
import { CreatePollComponentComponent } from './create-poll-component/create-poll-component.component';
|
||||||
|
import {StepsModule} from 'primeng/steps';
|
||||||
|
import {MenuItem} from 'primeng/api';
|
||||||
|
// import {FullCalendarModule} from 'primeng/fullcalendar';
|
||||||
|
import {ToastModule} from 'primeng/toast';
|
||||||
|
import {MessagesModule} from 'primeng/messages';
|
||||||
|
import {MessageModule} from 'primeng/message';
|
||||||
|
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||||
|
import {InputTextareaModule} from 'primeng/inputtextarea';
|
||||||
|
import {InputSwitchModule} from 'primeng/inputswitch';
|
||||||
|
import {CardModule} from 'primeng/card';
|
||||||
|
import {ButtonModule} from 'primeng/button';
|
||||||
|
import {InputTextModule} from 'primeng/inputtext';
|
||||||
|
import {SelectButtonModule} from 'primeng/selectbutton';
|
||||||
|
import {MenubarModule} from 'primeng/menubar';
|
||||||
|
import {CheckboxModule} from 'primeng/checkbox';
|
||||||
|
|
||||||
|
import dayGridPlugin from '@fullcalendar/daygrid'; // a plugin
|
||||||
|
import interactionPlugin from '@fullcalendar/interaction'; // a plugin
|
||||||
|
import timeGridPlugin from '@fullcalendar/timegrid';
|
||||||
|
|
||||||
|
import { FullCalendarModule } from '@fullcalendar/angular';
|
||||||
|
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
import { AnswerPollComponent } from './answer-poll/answer-poll.component';
|
||||||
|
import { AdminPollComponent } from './admin-poll/admin-poll.component';
|
||||||
|
import { DateagoPipe } from './dateago.pipe'; // the main connector. must go first
|
||||||
|
|
||||||
|
import { registerLocaleData } from '@angular/common';
|
||||||
|
import localeFr from '@angular/common/locales/fr';
|
||||||
|
import { UsernamePipePipe } from './username-pipe.pipe';
|
||||||
|
import { Selecteddate4userPipePipe } from './selecteddate4user-pipe.pipe';
|
||||||
|
import { ModalPollClosComponent } from './modal-poll-clos/modal-poll-clos.component';
|
||||||
|
import { TopBarComponent } from './top-bar/top-bar.component';
|
||||||
|
import { ShowCommentsComponent } from './show-comments/show-comments.component';
|
||||||
|
|
||||||
|
registerLocaleData(localeFr, 'fr');
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
AppComponent,
|
||||||
|
CardSmallComponentComponent,
|
||||||
|
HomeComponentComponent,
|
||||||
|
CreatePollComponentComponent,
|
||||||
|
AnswerPollComponent,
|
||||||
|
AdminPollComponent,
|
||||||
|
DateagoPipe,
|
||||||
|
UsernamePipePipe,
|
||||||
|
Selecteddate4userPipePipe,
|
||||||
|
ModalPollClosComponent,
|
||||||
|
TopBarComponent,
|
||||||
|
ShowCommentsComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
BrowserModule,
|
||||||
|
FormsModule,
|
||||||
|
HttpClientModule,
|
||||||
|
BrowserAnimationsModule,
|
||||||
|
AppRoutingModule,
|
||||||
|
StepsModule,
|
||||||
|
FullCalendarModule,
|
||||||
|
ToastModule,
|
||||||
|
MessagesModule,
|
||||||
|
MessageModule,
|
||||||
|
InputSwitchModule,
|
||||||
|
CardModule,
|
||||||
|
ButtonModule,
|
||||||
|
InputTextModule,
|
||||||
|
InputTextareaModule,
|
||||||
|
SelectButtonModule,
|
||||||
|
MenubarModule,
|
||||||
|
CheckboxModule,
|
||||||
|
NgbModule
|
||||||
|
],
|
||||||
|
providers: [],
|
||||||
|
bootstrap: [AppComponent],
|
||||||
|
|
||||||
|
|
||||||
|
})
|
||||||
|
export class AppModule { }
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
|
||||||
|
.SmallCard_Container {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.SmallCard {
|
||||||
|
background-color: white;
|
||||||
|
margin-right: 1rem;
|
||||||
|
padding: 2rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SmallCard_Image {
|
||||||
|
padding: 1rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SmallCard_Title {
|
||||||
|
padding: 1rem;
|
||||||
|
font-weight: 800;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SmallCard_Subtitle {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SmallCard:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<div class="SmallCard_Container">
|
||||||
|
<div *ngFor="let card of cards" class="SmallCard" [ngStyle]="card.style">
|
||||||
|
<div class="SmallCard_Image">
|
||||||
|
<img [src]="card.image" height="200px"/>
|
||||||
|
</div>
|
||||||
|
<div class="SmallCard_Title">
|
||||||
|
{{ card.title }}
|
||||||
|
</div>
|
||||||
|
<div class="SmallCard_Subtitle">
|
||||||
|
{{ card.subtitle }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { CardSmallComponentComponent } from './card-small-component.component';
|
||||||
|
|
||||||
|
describe('CardSmallComponentComponent', () => {
|
||||||
|
let component: CardSmallComponentComponent;
|
||||||
|
let fixture: ComponentFixture<CardSmallComponentComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ CardSmallComponentComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(CardSmallComponentComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
|
import { Card } from '../home-component/Card';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-card-small-component',
|
||||||
|
templateUrl: './card-small-component.component.html',
|
||||||
|
styleUrls: ['./card-small-component.component.css']
|
||||||
|
})
|
||||||
|
export class CardSmallComponentComponent implements OnInit {
|
||||||
|
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
cards: Card[];
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
.CreatePoll_Form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CreatePoll_Input {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CreatePoll_Input:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input, textarea {
|
||||||
|
font-weight: 400;
|
||||||
|
outline: none;
|
||||||
|
color: #102A43;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 17px;
|
||||||
|
border-radius: .25rem;
|
||||||
|
background-color: #F0F4F8;
|
||||||
|
border: 1px solid white;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus, textarea:focus {
|
||||||
|
border-color: #4D3DF7;
|
||||||
|
color: #102A43;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CreatePoll_Input input, textarea {
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CreatePoll_Input textarea {
|
||||||
|
max-width: 100%;
|
||||||
|
min-width: 100%;
|
||||||
|
min-height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CreatePoll_Buttons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CreatePoll_Button {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CreatePoll_LabelError {
|
||||||
|
color: #EF4E4E;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rbc-calendar {
|
||||||
|
height: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rbc-event {
|
||||||
|
background-color: #4D3DF7;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rbc-today {
|
||||||
|
background-color: #E6E6FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rbc-current-time-indicator {
|
||||||
|
background-color: #4D3DF7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rbc-slot-selection {
|
||||||
|
background-color: #C4C6FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rbc-time-view {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch {
|
||||||
|
display: inline-block;
|
||||||
|
height: 34px;
|
||||||
|
position: relative;
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch input {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider {
|
||||||
|
background-color: #ccc;
|
||||||
|
bottom: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
transition: .4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider:before {
|
||||||
|
background-color: #fff;
|
||||||
|
bottom: 4px;
|
||||||
|
content: "";
|
||||||
|
height: 26px;
|
||||||
|
left: 4px;
|
||||||
|
position: absolute;
|
||||||
|
transition: .4s;
|
||||||
|
width: 26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + .slider {
|
||||||
|
background-color: #4D3DF7;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + .slider:before {
|
||||||
|
transform: translateX(26px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider.round {
|
||||||
|
border-radius: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider.round:before {
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CreatePoll_Switch {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CreatePoll_Switch span {
|
||||||
|
margin-right: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Poll_Link {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Recap_Link {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Copy_Link {
|
||||||
|
border: none;
|
||||||
|
font-size: 1rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-green {
|
||||||
|
color: #199473;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Recap_Links {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
<div class="Container">
|
||||||
|
<img src="../../assets/flat_logo.png" alt="Logo Simba" height="50px" [ngStyle]="{ 'marginBottom': '1rem' }"/>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<p-toast></p-toast>
|
||||||
|
<p-steps [model]="items" [readonly]="false" [(activeIndex)]="step"></p-steps>
|
||||||
|
</div>
|
||||||
|
<div [hidden]="step!=0" class="stepsdemo-content">
|
||||||
|
<p-card>
|
||||||
|
<ng-template pTemplate="title">
|
||||||
|
Informations
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="subtitle">
|
||||||
|
Entrez les informations sur le rendez-vous à planifier
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="content">
|
||||||
|
<div class="p-fluid">
|
||||||
|
<div class="p-field">
|
||||||
|
<label for="titre">Titre de la réunion</label>
|
||||||
|
<input #titre="ngModel" id="titre" type="text" required pInputText
|
||||||
|
[(ngModel)]="poll.title"
|
||||||
|
[ngClass]="{'p-invalid': (titre.invalid && submitted) || (titre.dirty && titre.invalid)}">
|
||||||
|
<small *ngIf="(titre.invalid && submitted) || (titre.dirty && titre.invalid)"
|
||||||
|
class="p-error">Le titre est requis.</small>
|
||||||
|
</div>
|
||||||
|
<div class="p-field">
|
||||||
|
<label for="lieu">Lieu de la réunion</label>
|
||||||
|
<input #lieu="ngModel" id="lieu" type="text" required pInputText
|
||||||
|
[(ngModel)]="poll.location"
|
||||||
|
[ngClass]="{'p-invalid': (lieu.invalid && submitted) || (lieu.dirty && lieu.invalid)}">
|
||||||
|
<small class="p-error" *ngIf="(lieu.invalid && submitted )|| (lieu.dirty && lieu.invalid)">Le
|
||||||
|
lieu est requis.</small>
|
||||||
|
</div>
|
||||||
|
<div class="p-field">
|
||||||
|
<label for="desc">Description</label>
|
||||||
|
<textarea #desc="ngModel" id="desc" required pInputTextarea
|
||||||
|
[(ngModel)]="poll.description"
|
||||||
|
[ngClass]="{'p-invalid': (desc.invalid && submitted) || (desc.dirty && desc.invalid)}"></textarea>
|
||||||
|
<small class="p-error" *ngIf="(desc.invalid && submitted) || (desc.dirty && desc.invalid)">La description est requise.</small>
|
||||||
|
</div>
|
||||||
|
<div class="p-field">
|
||||||
|
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 1rem;font-weight: normal;">Repas</p>
|
||||||
|
<p-inputSwitch [ariaLabelledBy]="'repas'" #repas="ngModel" id="repas" [(ngModel)]="poll.has_meal"></p-inputSwitch>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="poll?.id" class="p-field">
|
||||||
|
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 1rem;font-weight: normal;">Sondage clos</p>
|
||||||
|
<p-inputSwitch #clos="ngModel" id="clos" [(ngModel)]="poll.clos"></p-inputSwitch>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="footer">
|
||||||
|
<div class="p-grid p-nogutter p-justify-end">
|
||||||
|
<p-button [disabled]=true label="Back" icon="pi pi-angle-left"></p-button>
|
||||||
|
|
||||||
|
<p-button class="float-right" label="Next" (onClick)="nextPage()" icon="pi pi-angle-right" iconPos="right"></p-button>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</p-card>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="step==1" class="stepsdemo-content">
|
||||||
|
<p-card>
|
||||||
|
<ng-template pTemplate="content">
|
||||||
|
<div class="p-fluid">
|
||||||
|
|
||||||
|
<div class="p-field">
|
||||||
|
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 1rem;font-weight: normal;">Avez vous un agenda avec un flux ics accessible ?</p>
|
||||||
|
<p-inputSwitch [(ngModel)]="hasics"></p-inputSwitch>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="hasics" class="p-field">
|
||||||
|
<label for="ics">URL ICS du participant</label>
|
||||||
|
<span class="p-input-icon-right">
|
||||||
|
<i *ngIf="loadics" class="pi pi-spin pi-spinner" ></i>
|
||||||
|
<input #mail="ngModel" id="ics" type="text" pInputText (change)="getICS()" [(ngModel)]="ics">
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<full-calendar #calendar [options]="options"></full-calendar>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="footer">
|
||||||
|
<div>
|
||||||
|
<p-button label="Back" (onClick)="prevPage1()" icon="pi pi-angle-left"></p-button>
|
||||||
|
<p-button class="float-right" label="Next" (onClick)="nextPage1()" icon="pi pi-angle-right" iconPos="right"></p-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</ng-template>
|
||||||
|
</p-card>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="step==2" class="stepsdemo-content">
|
||||||
|
<p-card>
|
||||||
|
<ng-template pTemplate="content">
|
||||||
|
Le sondage est créé. <BR>
|
||||||
|
Le lien pour participer est <a [href]="urlsondage" target="_blank">{{urlsondage}} </a>. <BR>
|
||||||
|
Le lien d'administration est <a [href]="urlsondageadmin" target="_blank">{{urlsondageadmin}}</a>.<BR>
|
||||||
|
Un salon a été créé de discussion pour cette réunion est accessible à cette adresse <a [href]="urlsalon" target="_blank">{{urlsalon}}</a>.<BR>
|
||||||
|
<span *ngIf="urlpad">Un pad a été créé pour cette réunion <a [href]="urlpad" target="_blank">{{urlpad}}</a>.</span><BR>
|
||||||
|
<BR>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="footer">
|
||||||
|
<div>
|
||||||
|
<p-button label="Back" (onClick)="prevPage1()" icon="pi pi-angle-left"></p-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</ng-template>
|
||||||
|
</p-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { CreatePollComponentComponent } from './create-poll-component.component';
|
||||||
|
|
||||||
|
describe('CreatePollComponentComponent', () => {
|
||||||
|
let component: CreatePollComponentComponent;
|
||||||
|
let fixture: ComponentFixture<CreatePollComponentComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ CreatePollComponentComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(CreatePollComponentComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,387 @@
|
|||||||
|
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
|
import { MenuItem, MessageService } from 'primeng/api';
|
||||||
|
import { PollService } from '../poll-service.service';
|
||||||
|
import { FullCalendarComponent } from '@fullcalendar/angular';
|
||||||
|
import frLocale from '@fullcalendar/core/locales/fr';
|
||||||
|
import { PollChoice, Poll, User } from '../model/model';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { CalendarOptions, EventInput } from '@fullcalendar/core';
|
||||||
|
import dayGridPlugin from '@fullcalendar/daygrid';
|
||||||
|
import interactionPlugin from '@fullcalendar/interaction';
|
||||||
|
import timeGridPlugin from '@fullcalendar/timegrid';
|
||||||
|
|
||||||
|
/*FullCalendarModule.registerPlugins([ // register FullCalendar plugins
|
||||||
|
dayGridPlugin,
|
||||||
|
interactionPlugin,
|
||||||
|
timeGridPlugin
|
||||||
|
]);*/
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-create-poll-component',
|
||||||
|
templateUrl: './create-poll-component.component.html',
|
||||||
|
styleUrls: ['./create-poll-component.component.css'],
|
||||||
|
providers: [MessageService, PollService, FullCalendarComponent]
|
||||||
|
})
|
||||||
|
export class CreatePollComponentComponent implements OnInit {
|
||||||
|
urlsondage = '';
|
||||||
|
urlsondageadmin = '';
|
||||||
|
urlsalon = '';
|
||||||
|
urlpad = '';
|
||||||
|
|
||||||
|
items: MenuItem[];
|
||||||
|
options: CalendarOptions;
|
||||||
|
|
||||||
|
step = 0;
|
||||||
|
|
||||||
|
slugid: string;
|
||||||
|
poll: Poll = {};
|
||||||
|
|
||||||
|
events: EventInput[] = [];
|
||||||
|
eventsfromics: EventInput[] = [];
|
||||||
|
allevents: EventInput[] = [];
|
||||||
|
|
||||||
|
|
||||||
|
calendarComponent: FullCalendarComponent;
|
||||||
|
hasics = false;
|
||||||
|
loadics = false;
|
||||||
|
ics: string;
|
||||||
|
|
||||||
|
@ViewChild('calendar') set content(content: FullCalendarComponent) {
|
||||||
|
if (content) { // initially setter gets called with undefined
|
||||||
|
this.calendarComponent = content;
|
||||||
|
const calendarApi = this.calendarComponent.getApi();
|
||||||
|
|
||||||
|
this.poll.pollChoices.forEach(pc => {
|
||||||
|
|
||||||
|
const evt =
|
||||||
|
{
|
||||||
|
title: '',
|
||||||
|
start: pc.startDate,
|
||||||
|
end: pc.endDate,
|
||||||
|
resourceEditable: false,
|
||||||
|
eventResizableFromStart: false,
|
||||||
|
extendedProps: {
|
||||||
|
choiceid: pc.id,
|
||||||
|
tmpId: this.getUniqueId(8)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
this.events.push(evt);
|
||||||
|
calendarApi.addEvent(evt, true);
|
||||||
|
|
||||||
|
});
|
||||||
|
calendarApi.setOption('validRange', {
|
||||||
|
start: this.getValidDate(),
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
submitted = false;
|
||||||
|
|
||||||
|
|
||||||
|
constructor(public messageService: MessageService, public pollService: PollService, private actRoute: ActivatedRoute) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.poll.pollChoices = [];
|
||||||
|
this.items = [{
|
||||||
|
label: 'Informations pour le rendez vous',
|
||||||
|
command: () => {
|
||||||
|
this.step = 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Choix de la date',
|
||||||
|
command: () => {
|
||||||
|
this.step = 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Résumé',
|
||||||
|
command: () => {
|
||||||
|
this.step = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
this.options = {
|
||||||
|
initialView: 'timeGridWeek',
|
||||||
|
plugins: [dayGridPlugin, interactionPlugin, timeGridPlugin],
|
||||||
|
|
||||||
|
// dateClick: this.handleDateClick.bind(this), // bind is important!
|
||||||
|
select: (selectionInfo) => {
|
||||||
|
console.log(selectionInfo);
|
||||||
|
const calendarApi = this.calendarComponent.getApi();
|
||||||
|
console.log(this.getUniqueId(8));
|
||||||
|
const evt = {
|
||||||
|
title: '',
|
||||||
|
start: selectionInfo.start,
|
||||||
|
end: selectionInfo.end,
|
||||||
|
resourceEditable: true,
|
||||||
|
eventResizableFromStart: true,
|
||||||
|
id: this.getUniqueId(8),
|
||||||
|
|
||||||
|
extendedProps: {
|
||||||
|
// tmpId: this.getUniqueId(8)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
calendarApi.addEvent(evt, true);
|
||||||
|
this.events.push(evt);
|
||||||
|
this.allevents.push(evt);
|
||||||
|
},
|
||||||
|
|
||||||
|
events: this.allevents,
|
||||||
|
editable: true,
|
||||||
|
droppable: true,
|
||||||
|
// selectMirror: true,
|
||||||
|
eventResizableFromStart: true,
|
||||||
|
selectable: true,
|
||||||
|
locale: frLocale,
|
||||||
|
themeSystem: 'bootstrap',
|
||||||
|
slotMinTime: '08:00:00',
|
||||||
|
slotMaxTime: '20:00:00',
|
||||||
|
eventMouseEnter: (mouseEnterInfo) => {
|
||||||
|
|
||||||
|
},
|
||||||
|
eventDrop: (info) => {
|
||||||
|
const evt = this.events.filter(e => e.id === info.event.id).pop();
|
||||||
|
evt.start = info.event.start;
|
||||||
|
evt.end = info.event.end;
|
||||||
|
},
|
||||||
|
eventResize: (info) => {
|
||||||
|
const evt = this.events.filter(e => e.id === info.event.id).pop();
|
||||||
|
const index = this.events.indexOf(evt);
|
||||||
|
evt.start = info.event.start;
|
||||||
|
evt.end = info.event.end;
|
||||||
|
},
|
||||||
|
eventClick: (info) => {
|
||||||
|
const evt = this.events.filter(e => e.id === info.event.id).pop();
|
||||||
|
if (evt != null){
|
||||||
|
const index = this.events.indexOf(evt);
|
||||||
|
if (index > -1) {
|
||||||
|
this.events.splice(index, 1);
|
||||||
|
}
|
||||||
|
const index1 = this.allevents.indexOf(evt);
|
||||||
|
if (index1 > -1) {
|
||||||
|
this.allevents.splice(index1, 1);
|
||||||
|
}
|
||||||
|
info.event.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
validRange: {
|
||||||
|
start: Date.now()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.actRoute.paramMap.subscribe(params => {
|
||||||
|
this.slugid = params.get('slugadminid');
|
||||||
|
console.log(this.slugid);
|
||||||
|
|
||||||
|
if (this.slugid != null) {
|
||||||
|
|
||||||
|
this.pollService.getPollBySlugAdminId(this.slugid).subscribe(p => {
|
||||||
|
if (p != null) {
|
||||||
|
this.poll = p;
|
||||||
|
} else {
|
||||||
|
this.messageService.add(
|
||||||
|
{
|
||||||
|
severity: 'warn',
|
||||||
|
summary: 'Un sondage avec cet identifiant n\'existe pas',
|
||||||
|
detail: 'Le sondage n\'a pas été récupéré'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
nextPage(): void {
|
||||||
|
|
||||||
|
if (this.poll.title && this.poll.location && this.poll.description) {
|
||||||
|
this.step = 1;
|
||||||
|
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.messageService.add(
|
||||||
|
{
|
||||||
|
severity: 'warn',
|
||||||
|
summary: 'Données incomplètes',
|
||||||
|
detail: 'Veuillez remplir les champs requis'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
this.submitted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextPage1(): void {
|
||||||
|
console.log(this.poll.id);
|
||||||
|
if (this.poll.id == null) {
|
||||||
|
this.events.forEach(e => {
|
||||||
|
this.poll.pollChoices.push({
|
||||||
|
startDate: e.start as any,
|
||||||
|
endDate: e.end as any,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.pollService.createPoll(this.poll).subscribe(p1 => {
|
||||||
|
this.poll = p1;
|
||||||
|
this.urlsondage = window.location.protocol + '//' + window.location.host + '/answer/' + p1.slug;
|
||||||
|
this.urlsondageadmin = window.location.protocol + '//' + window.location.host + '/admin/' + p1.slugAdmin;
|
||||||
|
this.urlsalon = p1.tlkURL;
|
||||||
|
this.urlpad = p1.padURL;
|
||||||
|
this.step = 2;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
|
||||||
|
const toKeep: PollChoice[] = [];
|
||||||
|
this.events.filter(c => c.extendedProps != null && c.extendedProps.choiceid != null).forEach(e => {
|
||||||
|
toKeep.push(this.poll.pollChoices.filter(c1 => c1.id === e.extendedProps.choiceid)[0]);
|
||||||
|
});
|
||||||
|
this.poll.pollChoices = toKeep;
|
||||||
|
this.poll.pollChoices.forEach(c => {
|
||||||
|
const res = this.events.filter(c1 => c1.extendedProps != null &&
|
||||||
|
c1.extendedProps.choiceid != null && c1.extendedProps.choiceid === c.id)[0];
|
||||||
|
c.startDate = res.start as any;
|
||||||
|
c.endDate = res.end as any;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.events.filter(c => c.extendedProps == null || c.extendedProps.choiceid == null).forEach(e => {
|
||||||
|
this.poll.pollChoices.push({
|
||||||
|
startDate: e.start as any,
|
||||||
|
endDate: e.end as any,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
console.log(this.events);
|
||||||
|
console.log(this.poll.pollChoices);
|
||||||
|
|
||||||
|
this.pollService.updtatePoll(this.poll).subscribe(p1 => {
|
||||||
|
this.poll = p1;
|
||||||
|
this.urlsondage = 'http://localhost:4200/answer/' + p1.slug;
|
||||||
|
this.urlsondageadmin = 'http://localhost:4200/admin/' + p1.slugAdmin;
|
||||||
|
this.urlsalon = p1.tlkURL;
|
||||||
|
this.urlpad = p1.padURL;
|
||||||
|
this.step = 2;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
prevPage1(): void {
|
||||||
|
|
||||||
|
this.step = this.step - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private getUniqueId(parts: number): string {
|
||||||
|
const stringArr = [];
|
||||||
|
for (let i = 0; i < parts; i++) {
|
||||||
|
// tslint:disable-next-line:no-bitwise
|
||||||
|
const S4 = (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
|
||||||
|
stringArr.push(S4);
|
||||||
|
}
|
||||||
|
return stringArr.join('-');
|
||||||
|
}
|
||||||
|
|
||||||
|
private getValidDate(): number {
|
||||||
|
if (this.poll.id != null) {
|
||||||
|
if ((this.poll.pollChoices[0].startDate as any - Date.now()) < 0) {
|
||||||
|
return this.poll.pollChoices[0].startDate as any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Date.now();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getICS(): void {
|
||||||
|
this.loadics = true;
|
||||||
|
this.pollService.getICS(this.slugid, this.ics).subscribe(res => {
|
||||||
|
this.loadics = false;
|
||||||
|
|
||||||
|
const calendarApi = this.calendarComponent.getApi();
|
||||||
|
if (res.eventdtos.length > 0) {
|
||||||
|
this.eventsfromics.forEach(eid => {
|
||||||
|
const index = this.allevents.indexOf(eid);
|
||||||
|
if (index > -1) {
|
||||||
|
this.allevents.splice(index, 1);
|
||||||
|
}
|
||||||
|
calendarApi.getEventById(eid.id)?.remove();
|
||||||
|
});
|
||||||
|
this.eventsfromics = [];
|
||||||
|
}
|
||||||
|
console.log(res);
|
||||||
|
|
||||||
|
res.eventdtos.forEach(evtdto => { // calendarApi.next();
|
||||||
|
const evt1 =
|
||||||
|
{
|
||||||
|
title: evtdto.description,
|
||||||
|
start: evtdto.startDate,
|
||||||
|
end: evtdto.endDate,
|
||||||
|
resourceEditable: false,
|
||||||
|
editable: false,
|
||||||
|
droppable: false,
|
||||||
|
selectable: false,
|
||||||
|
eventResizableFromStart: false,
|
||||||
|
id: this.getUniqueId(8),
|
||||||
|
|
||||||
|
backgroundColor: 'red',
|
||||||
|
extendedProps: {
|
||||||
|
fromics: true
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
const eventAPI = calendarApi.addEvent(evt1, true);
|
||||||
|
this.eventsfromics.push(evt1);
|
||||||
|
this.allevents.push(evt1);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
const unselected = this.events.map(ev => ev.extendedProps.choiceid);
|
||||||
|
res.selectedChoices.forEach(e => {
|
||||||
|
const index = unselected.indexOf(e);
|
||||||
|
if (index > -1) {
|
||||||
|
unselected.splice(index, 1);
|
||||||
|
}
|
||||||
|
const evt1 = this.events.filter(ev => ev.extendedProps.choiceid === e)[0];
|
||||||
|
|
||||||
|
const evt2 = calendarApi.getEventById(evt1.id);
|
||||||
|
evt1.backgroundColor = 'red';
|
||||||
|
evt1.extendedProps.selected = false;
|
||||||
|
evt2.setProp('backgroundColor', 'red');
|
||||||
|
// this.poll.pollChoices.filter(pc => pc.id === evt1.extendedProps.choiceid)[0].users.push({ id: -1 });
|
||||||
|
});
|
||||||
|
unselected.forEach(e => {
|
||||||
|
const evt1 = this.events.filter(ev => ev.extendedProps.choiceid === e)[0];
|
||||||
|
|
||||||
|
const evt2 = calendarApi.getEventById(evt1.id);
|
||||||
|
evt1.backgroundColor = 'green';
|
||||||
|
evt1.extendedProps.selected = true;
|
||||||
|
evt2.setProp('backgroundColor', 'green');
|
||||||
|
this.poll.pollChoices.filter(pc => pc.id === evt1.extendedProps.choiceid)[0].users.push({ id: -1 });
|
||||||
|
});
|
||||||
|
}, (err) => {
|
||||||
|
this.loadics = false;
|
||||||
|
|
||||||
|
this.messageService.add(
|
||||||
|
{
|
||||||
|
severity: 'warn',
|
||||||
|
summary: 'Ne peut récupérer l\'agenda à partir de l\'adresse de l\'ics',
|
||||||
|
detail: 'Une erreur s\'est produite au moment de la récupération de l\'agenda'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { DateagoPipe } from './dateago.pipe';
|
||||||
|
|
||||||
|
describe('DateagoPipe', () => {
|
||||||
|
it('create an instance', () => {
|
||||||
|
const pipe = new DateagoPipe();
|
||||||
|
expect(pipe).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
41
ansible/files/doodlestudent/front/src/app/dateago.pipe.ts
Normal file
41
ansible/files/doodlestudent/front/src/app/dateago.pipe.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { Pipe, PipeTransform } from '@angular/core';
|
||||||
|
|
||||||
|
@Pipe({
|
||||||
|
name: 'dateago',
|
||||||
|
pure: true
|
||||||
|
|
||||||
|
})
|
||||||
|
export class DateagoPipe implements PipeTransform {
|
||||||
|
|
||||||
|
transform(value: any, args?: any): any {
|
||||||
|
if (value) {
|
||||||
|
const seconds = Math.floor((+new Date() - +new Date(value)) / 1000);
|
||||||
|
if (seconds < 29) { // less than 30 seconds ago will show as 'Just now'
|
||||||
|
return 'quelques secondes';
|
||||||
|
}
|
||||||
|
const intervals = {
|
||||||
|
année: 31536000,
|
||||||
|
mois: 2592000,
|
||||||
|
semaine: 604800,
|
||||||
|
jour: 86400,
|
||||||
|
heure: 3600,
|
||||||
|
minute: 60,
|
||||||
|
seconde: 1
|
||||||
|
};
|
||||||
|
let counter;
|
||||||
|
// tslint:disable-next-line:forin
|
||||||
|
for (const i in intervals) {
|
||||||
|
counter = Math.floor(seconds / intervals[i]);
|
||||||
|
if (counter > 0){
|
||||||
|
if (counter === 1 || i === 'mois') {
|
||||||
|
return counter + ' ' + i + ''; // singular (1 day ago)
|
||||||
|
} else {
|
||||||
|
return counter + ' ' + i + 's'; // plural (2 days ago)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
export class Card {
|
||||||
|
constructor(public image: string, public style: any, public title: string, public subtitle: string){
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
.Container {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 2rem auto;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Home_Container {
|
||||||
|
width: 1024px;
|
||||||
|
margin: 0 auto;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Home_Wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Home_Logo {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Home_Button {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Home_CreateLink {
|
||||||
|
padding: 1rem;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #43dbac;
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 1.3rem;
|
||||||
|
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.10);
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<div class="Home_Container">
|
||||||
|
<div class="Home_Wrapper">
|
||||||
|
<div class="Home_Logo">
|
||||||
|
<img src="../../assets/Logo.png" alt="Logo Simba" height="130px"/>
|
||||||
|
</div>
|
||||||
|
<app-card-small-component [cards]="cards"></app-card-small-component>
|
||||||
|
<div class="Home_Button">
|
||||||
|
<a routerLink="/create" class="Home_CreateLink">Créer votre poll !</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { HomeComponentComponent } from './home-component.component';
|
||||||
|
|
||||||
|
describe('HomeComponentComponent', () => {
|
||||||
|
let component: HomeComponentComponent;
|
||||||
|
let fixture: ComponentFixture<HomeComponentComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ HomeComponentComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(HomeComponentComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { CardSmallComponentComponent } from '../card-small-component/card-small-component.component';
|
||||||
|
import {Card} from './Card';
|
||||||
|
@Component({
|
||||||
|
selector: 'app-home-component',
|
||||||
|
templateUrl: './home-component.component.html',
|
||||||
|
styleUrls: ['./home-component.component.css'],
|
||||||
|
providers: [CardSmallComponentComponent]
|
||||||
|
|
||||||
|
})
|
||||||
|
export class HomeComponentComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
|
||||||
|
cards: Card[] = [];
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
|
||||||
|
this.cards.push(new Card('assets/1.png', {backgroundColor: '#44baf2', color: 'white'}, 'Créez un sondage', 'Définissez plusieurs créneaux pour votre réunion.'));
|
||||||
|
this.cards.push(new Card('assets/2.png', {backgroundColor: '#fc506d', color: 'white'}, 'Envoyez vos invitations', 'Les participants aux sondages pourront voter pour les dates qui leur conviennent le mieux !'));
|
||||||
|
this.cards.push(new Card('assets/3.png', {backgroundColor: '#8f3ee8', color: 'white'}, 'Faites votre choix', 'Vous pourrez obtenir en direct les résultats du sondage afin de choisir au mieux la meilleure proposition.'));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header text-center justify-content-center">
|
||||||
|
<h4 class="modal-title" id="modal-basic-title">Le sondage est maintenant clos</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
|
||||||
|
<div class="d-flex justify-content-center">
|
||||||
|
La date retenue pour le soundage est le:
|
||||||
|
</div>
|
||||||
|
<BR>
|
||||||
|
<div class="d-flex justify-content-center">
|
||||||
|
<b>{{poll?.selectedChoice?.startDate | date:'EEEE d LLLL': 'CEST':'fr'}}</b>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex justify-content-center">
|
||||||
|
<b> de {{poll?.selectedChoice?.startDate | date:'H:mm'}}</b>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex justify-content-center">
|
||||||
|
<b> - </b>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-flex justify-content-center">
|
||||||
|
<b> {{poll?.selectedChoice?.endDate | date:'H:mm'}}</b>
|
||||||
|
</div>
|
||||||
|
<BR>
|
||||||
|
Le lieu sera {{poll?.location}}
|
||||||
|
<BR>
|
||||||
|
<div *ngIf="poll?.padURL">
|
||||||
|
Un pad est ouvert <a [href]="poll?.padURL" target="_blank">ici</a>
|
||||||
|
</div>
|
||||||
|
<BR>
|
||||||
|
<div *ngIf="poll?.tlkURL">
|
||||||
|
Un salon de discussion est ouvert <a [href]="poll?.tlkURL" target="_blank">ici</a>
|
||||||
|
</div>
|
||||||
|
<BR>
|
||||||
|
<div *ngIf="poll?.has_meal">Un repas est prévu pour ce meeting.
|
||||||
|
</div>
|
||||||
|
<BR>
|
||||||
|
<div *ngIf="poll?.description">
|
||||||
|
L'ordre du jour est le suivant:
|
||||||
|
{{poll.description}}
|
||||||
|
</div>
|
||||||
|
<BR>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-outline-dark" (click)="dismissModalAndNavigate()">Retour</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ModalPollClosComponent } from './modal-poll-clos.component';
|
||||||
|
|
||||||
|
describe('ModalPollClosComponent', () => {
|
||||||
|
let component: ModalPollClosComponent;
|
||||||
|
let fixture: ComponentFixture<ModalPollClosComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ ModalPollClosComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ModalPollClosComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
|
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
import { Poll } from '../model/model';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-modal-poll-clos',
|
||||||
|
templateUrl: './modal-poll-clos.component.html',
|
||||||
|
styleUrls: ['./modal-poll-clos.component.css'],
|
||||||
|
providers: [NgbActiveModal]
|
||||||
|
})
|
||||||
|
export class ModalPollClosComponent implements OnInit {
|
||||||
|
|
||||||
|
@Input() poll: Poll;
|
||||||
|
constructor(public activeModal: NgbActiveModal, public router: Router) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
dismissModalAndNavigate(): void{
|
||||||
|
this.activeModal.close();
|
||||||
|
window.location.href = '/';
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
57
ansible/files/doodlestudent/front/src/app/model/model.ts
Normal file
57
ansible/files/doodlestudent/front/src/app/model/model.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
export interface Poll {
|
||||||
|
createdAt?: Date;
|
||||||
|
description?: string;
|
||||||
|
has_meal?: boolean;
|
||||||
|
id?: number;
|
||||||
|
location?: string;
|
||||||
|
padURL?: string;
|
||||||
|
pollChoices?: PollChoice[];
|
||||||
|
selectedChoice ?: PollChoice;
|
||||||
|
pollComments?: PollCommentElement[];
|
||||||
|
pollMealPreferences?: PollCommentElement[];
|
||||||
|
slug?: string;
|
||||||
|
slugAdmin?: string;
|
||||||
|
title?: string;
|
||||||
|
tlkURL?: string;
|
||||||
|
updatedAt?: Date;
|
||||||
|
clos ?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PollChoice {
|
||||||
|
endDate?: Date;
|
||||||
|
id?: number;
|
||||||
|
startDate?: Date;
|
||||||
|
users?: User[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface User {
|
||||||
|
id?: number;
|
||||||
|
username?: string;
|
||||||
|
mail?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ChoiceUser {
|
||||||
|
username?: string;
|
||||||
|
mail?: string;
|
||||||
|
pref?: string;
|
||||||
|
ics?: string;
|
||||||
|
choices?: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PollCommentElement {
|
||||||
|
content?: string;
|
||||||
|
id?: number;
|
||||||
|
auteur?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EventDTO{
|
||||||
|
startDate?: Date;
|
||||||
|
endDate?: Date;
|
||||||
|
description?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface EventDTOAndSelectedChoice {
|
||||||
|
eventdtos?: EventDTO[];
|
||||||
|
selectedChoices?: number[];
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { PollServiceService } from './poll-service.service';
|
||||||
|
|
||||||
|
describe('PollServiceService', () => {
|
||||||
|
let service: PollServiceService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(PollServiceService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Poll, PollChoice, User, ChoiceUser, PollCommentElement, EventDTOAndSelectedChoice } from './model/model';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class PollService {
|
||||||
|
|
||||||
|
constructor(private http: HttpClient) { }
|
||||||
|
|
||||||
|
public createPoll(p: Poll): Observable<Poll> {
|
||||||
|
console.log('create poll');
|
||||||
|
return this.http.post<Poll>('/api/polls', p);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public updtatePoll(p: Poll): Observable<Poll> {
|
||||||
|
return this.http.put<Poll>('/api/poll/update1', p);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public getPollBySlugId(slugId: string): Observable<Poll>{
|
||||||
|
return this.http.get<Poll>('/api/poll/slug/' + slugId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getComentsBySlugId(slugId: string): Observable<PollCommentElement[]>{
|
||||||
|
return this.http.get<PollCommentElement[]>('/api/polls/' + slugId + '/comments');
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPollBySlugAdminId(slugId: string): Observable<Poll>{
|
||||||
|
return this.http.get<Poll>('/api/poll/aslug/' + slugId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateChoice4user( cu: ChoiceUser): Observable<User>{
|
||||||
|
|
||||||
|
return this.http.post<User>('/api/poll/choiceuser/', cu);
|
||||||
|
}
|
||||||
|
|
||||||
|
public addComment4Poll( slug: string, comment: PollCommentElement ): Observable<PollCommentElement>{
|
||||||
|
|
||||||
|
return this.http.post<PollCommentElement>('/api/poll/comment/' + slug, comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
selectEvent(choiceid: number): Observable<void> {
|
||||||
|
return this.http.post<void>('/api/poll/selectedchoice/' + choiceid, null);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
getICS(slug: string, ics: string): Observable<EventDTOAndSelectedChoice> {
|
||||||
|
return this.http.get<EventDTOAndSelectedChoice>('/api/ics/polls/' + slug + '/' + btoa(ics));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { Selecteddate4userPipePipe } from './selecteddate4user-pipe.pipe';
|
||||||
|
|
||||||
|
describe('Selecteddate4userPipePipe', () => {
|
||||||
|
it('create an instance', () => {
|
||||||
|
const pipe = new Selecteddate4userPipePipe();
|
||||||
|
expect(pipe).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user