Compare commits

...

131 Commits
v0.1.0 ... main

Author SHA1 Message Date
Edouard DUPIN
90446717d0 qsdfqsdf 2025-07-04 18:14:33 +02:00
Edouard DUPIN
1067a3ea88 [FEAT] update size of Image fomr 1.3GB to 186MB 2025-05-04 22:41:56 +02:00
Edouard DUPIN
7c5c0de697 [FEAT] remove old migration and midration to mongo is OK 2025-05-04 22:41:20 +02:00
Edouard DUPIN
061fc51138 [RELEASE] Release v1.2.0 2025-05-03 11:05:46 +02:00
Edouard DUPIN
c5b714b609 [FEAT] update last archidata 2025-05-03 11:04:41 +02:00
Edouard DUPIN
d23f1a945c [FEAT] upgrade to MongoDb and use ObjectId 2025-05-01 23:10:05 +02:00
50f0c903f4 [FEAT] change namespace and update to the last archidata 2025-04-14 22:21:29 +02:00
15dfdd8605 [FEAT] some intrinsec upgrade and add basic test in back 2025-03-30 23:34:45 +02:00
ba7b6e4755 [FEAT] Play all the playlist in background when phone is stop.
the explanation is the android does not support to update the GUI interface
when the application is down, but it support some update of the playing file
in the audio tag.
2025-03-23 21:01:54 +01:00
3beafab7e1 [FEAT] upgrade pependency in front lock file 2025-03-23 21:00:11 +01:00
9cf41dd094 [FIX] icon in application mode 2025-03-23 14:19:53 +01:00
4caec9a54a [FEAT] review the loggin model to be satble and efficient with user interactions
Signed-off-by: Edouard DUPIN <yui.heero@gmail.com>
2025-03-23 14:11:30 +01:00
83f8ec0e9b [FEAT] prevent application to refresh whenit is at end of page (native CSS) 2025-03-23 14:10:22 +01:00
4993c17136 [FEAT] set manifest to consider web pasge as an application 2025-03-23 14:09:36 +01:00
401e2ce3c5 [FEAT] block reload on scoll 2025-03-22 12:12:08 +01:00
693d59ab68 [FEAT] review and normailise title of the topBar
Signed-off-by: Edouard DUPIN <yui.heero@gmail.com>
2025-03-22 12:11:51 +01:00
4eff2e55ef [FIX] session management 2025-03-22 12:11:19 +01:00
1e890f9524 [FIX] remove develop mode in production 2025-03-22 12:11:06 +01:00
dbb2527cb8 [FEAT] update dependecy 2025-03-22 12:10:45 +01:00
d65faa8810 [FIX] new file update and create 2025-03-22 12:10:32 +01:00
9c9476b052 [FEAT] increase feature of topBar 2025-03-22 12:09:37 +01:00
3e92c2b74a [FEAT] update new archidata 2025-03-22 12:09:18 +01:00
a7134c01ed [FIX] readme title 2025-03-22 12:06:05 +01:00
88b27e5f39 [FIX] deploy 2025-02-11 22:23:55 +01:00
eaf0f5688e [FIX] add end correction 2025-02-11 22:06:57 +01:00
4ebfa4e2ca [FIX] form basic models 2025-02-11 21:35:42 +01:00
c65e7d5e25 [DEV] continue refacto 2025-02-11 00:10:38 +01:00
de61cc156f [DEV] update from karso 2025-02-10 21:50:04 +01:00
4d18438914 [FEAT] update new archidata 2025-02-10 19:14:12 +01:00
80dfabcf48 [FEAT] update new archidata 2025-02-10 00:46:26 +01:00
83bfeda4ca [FEAT] Chakra V3 full operational 2025-01-25 01:34:11 +01:00
c489fabb77 [theme and reciepice 2025-01-24 21:57:04 +01:00
d52052de90 [DEV] test step between receipice and direct managemnt 2025-01-20 18:45:19 +01:00
91defa42c2 [FIX] chakra ui component is not full 2025-01-14 18:56:03 +01:00
2812d21782 [FEAT] doen not work: regacto of the Chakra-ui 3.3 ==> very bad port 2025-01-13 21:59:06 +01:00
eb5a366a12 [FEAT] add on air 2025-01-11 20:48:22 +01:00
6b801d250f [FIX] remove a stupid log... 2025-01-11 19:31:51 +01:00
01fad1b9d4 [FEAT] add a shuffle in the artist list.
This feature take a random on the artist and keep the 25 first and ge a single track for each artist.
2025-01-11 19:30:01 +01:00
371bea79f9 [FEAT] add a tool to manage a shuffle of an array 2025-01-11 19:28:51 +01:00
35725e1320 [FIX] sign-in in production mode 2025-01-11 19:28:30 +01:00
d6a8c7d23f [FIX] build version 2025-01-11 18:12:27 +01:00
3c604e9593 [VERSION] update dev tag version 2025-01-11 17:33:31 +01:00
43d8108270 [RELEASE] Release v1.1.0 2025-01-11 17:33:21 +01:00
1a883193d0 [DEPENDENCY] update release of archidata 2025-01-11 17:32:43 +01:00
78b1970ba9 [FEAT] (front) Update versions of dependency 2025-01-11 17:31:01 +01:00
746d5dff96 [FIX] test will not able to connect on port 80 2025-01-11 17:31:01 +01:00
8780ea8e63 [FIX] initialization error 2025-01-11 17:31:01 +01:00
8911eed0fb [FEAT] update NCU to only update vertion but not the major 2025-01-11 17:31:01 +01:00
1a3652472e [FIX] update the error response with OID instead of UUID 2025-01-11 17:31:01 +01:00
2e62577103 [FIX] (front) fix the environment semection in production mode 2025-01-11 17:31:01 +01:00
653e77160b [FEAT] update logger to well support the backend 2025-01-11 17:31:01 +01:00
3898a6bf4f [DEV] remove old logger system 2025-01-11 17:31:01 +01:00
448cf1569b [FIX] remove old loger system 2025-01-11 17:31:01 +01:00
d3e2b3e601 [VERSION] update dev tag version 2025-01-06 23:49:35 +01:00
8f026d47e1 [RELEASE] Release v1.0.4 2025-01-06 23:48:46 +01:00
de17fc228d [FIX] migration file error 2025-01-06 23:48:21 +01:00
3434a48573 [VERSION] update dev tag version 2025-01-06 23:30:02 +01:00
8f1934e323 [RELEASE] Release v1.0.2 2025-01-06 23:29:13 +01:00
1631d1cab9 [FIX] logger dependency error 2025-01-06 23:24:45 +01:00
b71ea1bcd8 [FEAT] some update 2025-01-06 00:50:38 +01:00
db1e387ac8 [FIX] set work again 2025-01-06 00:27:09 +01:00
762a1aeced [VERSION] update dev tag version 2025-01-05 22:06:58 +01:00
670b5537bb [RELEASE] Release v1.0.0 2025-01-05 22:06:38 +01:00
16e7197939 [FEAT] fix archidata_vertion for release 2025-01-05 22:03:44 +01:00
98d213b01e [FEAT] Bridge 'JDK logging API' to 'SLF4J' 2025-01-05 21:53:42 +01:00
0260b4d408 [FEAT] update to new API of archidata 2025-01-05 20:08:56 +01:00
f03a18c34c [RELEASE] prepare release 2024-09-20 19:51:17 +02:00
6107b95dcd [FEAT] better management of upload files 2024-09-20 22:19:10 +02:00
e9af64405b [DEV] add checker 2024-09-19 21:22:35 +02:00
725cd54d92 [FEAT] basic pop-up and upload a single file (can not read) 2024-09-01 23:10:40 +02:00
08eb0f878a [FEAT] ready gor update and suggestion 2024-09-01 23:10:40 +02:00
619e9aa4b8 [FEAT] update the Slector to support add element 2024-09-16 21:53:29 +02:00
6181022814 [FEAT] add basic page of the ADD media (kanva OK, no upload and check) 2024-09-16 00:06:37 +02:00
3f96b870a0 [FEAT] ready to generate production 2024-09-16 00:05:53 +02:00
5eba6d32b6 [DEV] build docker and correct some typing 2024-09-15 17:58:34 +02:00
a24484b5f9 [FEAT] ignore env_dev/data* 2024-09-15 17:58:34 +02:00
77f8527fc4 [FEAT] rename front2 as front 2024-09-15 17:58:24 +02:00
75cca15898 [FEAT] remove angular front 2024-09-15 17:56:48 +02:00
f0b2a859db [FEAT] correct some connection/disconnection of SSO 2024-09-15 17:56:48 +02:00
a6fe889d4c [FEAT] better covers, Icons and work on better display for the phones 2024-09-15 17:56:48 +02:00
ad7ff2c340 [FEAT] upgrade the api generation and search how to manage cover auto-change 2024-09-15 17:56:48 +02:00
1271885124 [FIX] correct the API generation 2024-09-15 17:56:48 +02:00
dde514a1a0 [FIX] missing migration 2024-09-15 17:56:48 +02:00
dc7131843d [FEAT] continue integration 2024-09-15 17:56:48 +02:00
091390e025 [FEAT] add edit of album and artist
Missing cover that might be studied
2024-09-15 17:56:48 +02:00
3377f80fbc [FEAT] generize the form model 2024-09-15 17:56:48 +02:00
4cf71f35b6 [FEAT] review some namings 2024-09-15 17:56:48 +02:00
faaf3b280b [FEAT] live edit, remove is operational with confirm pop-in.
need to upgrade the code to be reusable
2024-09-15 17:56:48 +02:00
0687369164 [DEV] test 2 2024-09-15 17:56:48 +02:00
147264eb7f [DEV] test 1 2024-09-15 17:56:48 +02:00
ec93c31acb Work on form and basic tools I need 2024-09-15 17:56:48 +02:00
873f0acff5 [DEV] integrate menue on thack 2024-09-15 17:56:48 +02:00
244f8a988e [DEV] remove all async it is too slow... 2024-09-15 17:56:48 +02:00
d49e1d06fe [FEAT] so many things .... 2024-09-15 17:56:48 +02:00
53c3cfefe3 [FEAT] corect the useMemo and better interface of audio player 2024-09-15 17:56:48 +02:00
90fb1ed411 [FEAT] add album direct diaplay 2024-09-15 17:56:48 +02:00
30bc82edb3 [FEAT] basic working karusic 2024-09-15 17:56:40 +02:00
1d4c547d89 [DEV] first vesion of karisic in react + chakra-ui 2024-08-22 11:29:57 +02:00
21d53b77f2 [FEAT] many renaming 2024-08-15 11:47:50 +02:00
3b27edfa3b [VERSION] update dev tag version 2024-05-12 12:03:31 +02:00
6155ca5c0b [RELEASE] Release v0.2.0 2024-05-12 12:03:31 +02:00
45eb56a6fe [DEV] update relase for island 2024-05-12 11:57:08 +02:00
9e0a834b48 [DEV] update readme 2024-04-15 00:57:00 +02:00
d5f335e1e7 [DEV] add progress callback 2024-04-15 00:56:45 +02:00
df384cc8be [DEV] correct version with some ibrary update 2024-04-13 09:03:05 +02:00
4b545ebbe2 [FIX] update dockerfile 2024-04-07 19:25:07 +02:00
eb3cd1b1fe [DEV] all is operational 2024-04-07 19:13:06 +02:00
95e2e03686 [DEV] all work well 2024-04-07 17:08:43 +02:00
2402fc31ed [DEV] it works without security 2024-04-07 17:05:36 +02:00
763875fbdf {DEV] still work 2024-04-07 09:02:17 +02:00
4ff2b247b4 [DEV] update to basic work 2024-04-06 13:08:12 +02:00
e4246750c7 [DEV] Run but does not realy start 2024-04-05 23:51:48 +02:00
04633240b3 [DEV] find how to fix the error but not Ok with the result 2024-04-03 00:34:47 +02:00
c76a339caf [DEV] update new model with remote library (not work) 2024-03-29 18:39:33 +01:00
8a5758af78 [DEV] remove submodule and correct first init 2024-03-23 07:27:27 +01:00
e05fe70f80 [DEV] ready for deply new model of data UUID 2024-03-19 23:17:05 +01:00
f6f9fa199a [DEV] update new version 2024-03-19 19:17:04 +01:00
a1684f0fc0 [DEV] update new model 2024-03-19 08:37:07 +01:00
cebf7d35fb [DEV] update all the model 2024-03-17 23:45:38 +01:00
5d8dab3742 [DEV] finish base of port but not tested 2024-03-15 07:59:23 +01:00
9a3f28553d [DEV] basic migration of to the new generation interface 2024-03-11 00:07:46 +01:00
48e14212db [DEV] implement partial migration to support new uuid for data and local cover of model 2024-03-04 00:14:08 +01:00
c3e2b7240b [DEV] migrate with succes to angular17 2024-02-26 00:01:37 +01:00
0af1bbfb52 [DEV] correct the backend can not insert trach artist ... fail t in archidata model 2024-02-26 00:01:05 +01:00
619973459a [DEV] continue migration to Angular17 2024-02-23 00:37:47 +01:00
d37ce25621 [DEV] update to angular17 2024-02-15 22:59:35 +01:00
b4157877c3 [DEV] add search in artist and album 2024-01-27 19:34:53 +01:00
883866d5f6 [DEV] update display better 2024-01-27 18:09:29 +01:00
247064e412 [DEV] remove test replace 2024-01-25 23:39:41 +01:00
70c63882e4 [DEV] corrrect the desplay of the player overflow (and some redesign) 2024-01-25 23:37:36 +01:00
9da93a2831 [DEV] update dev tag version 2024-01-19 22:50:09 +01:00
401 changed files with 37866 additions and 35730 deletions

4
.gitignore vendored
View File

@ -53,6 +53,8 @@ testem.log
# System Files
.DS_Store
Thumbs.db
/env_dev/data
/env_dev/dataMongo
backPY/env
@ -62,3 +64,5 @@ __pycache__
.design/
.vscode/
front/storybook-static
back/bin

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "front/src/common"]
path = front/src/common
url = ../common_web.git

View File

@ -1,7 +1,32 @@
#!/bin/bash
version_file="../version.txt"
# update new release dependency
cd back
mvn versions:set -DnewVersion=$(cat ../version.txt)
# update the Maven version number
mvn versions:set -DnewVersion=$(sed 's/dev/SNAPSHOT/g' $version_file)
if grep -q "DEV" "$version_file"; then
# update all versions release of dependency
mvn versions:use-latest-releases
# update our manage dependency as snapshoot
mvn versions:use-latest-versions -Dincludes=kangaroo-and-rabbit
else
# update our manage dependency as release (must be done before)
mvn versions:use-latest-releases -Dincludes=kangaroo-and-rabbit
fi
cd -
cd front
if grep -q "dev" "$version_file"; then
# update all dependency
pnpm install
pnpm run update_packages
else
# in case of release ==> can not do it automatically ...
echo not implemented
fi
cd -

View File

@ -3,23 +3,31 @@
## buyilding-end install applications:
##
######################################################################################
FROM archlinux:base-devel AS builder
FROM archlinux:base-devel AS common
# update system
RUN pacman -Syu --noconfirm && pacman-db-upgrade \
&& pacman -S --noconfirm jdk-openjdk maven npm \
&& pacman -S --noconfirm jdk-openjdk wget\
&& pacman -Scc --noconfirm
ENV PATH /tmp/node_modules/.bin:$PATH
WORKDIR /tmp
FROM common AS builder
# update system
RUN pacman -Syu --noconfirm && pacman-db-upgrade \
&& pacman -S --noconfirm maven npm pnpm \
&& pacman -Scc --noconfirm
ENV PATH=/tmp/node_modules/.bin:$PATH
######################################################################################
##
## Build back:
##
######################################################################################
FROM builder AS buildBack
COPY back/pom.xml /tmp
COPY back/src /tmp/src/
FROM builder AS build_back
COPY back/pom.xml ./
COPY back/Formatter.xml ./
COPY back/src ./src/
RUN mvn clean compile assembly:single
######################################################################################
@ -27,53 +35,70 @@ RUN mvn clean compile assembly:single
## Build front:
##
######################################################################################
FROM builder AS buildFront
FROM builder AS dependency_front
ADD front/package-lock.json \
front/package.json \
front/karma.conf.js \
front/protractor.conf.js \
/tmp/
RUN echo "@kangaroo-and-rabbit:registry=https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/npm/" > /root/.npmrc
ADD front/package.json \
front/pnpm-lock.yaml \
./
ADD front/src/theme ./src/theme
# install and cache app dependencies
RUN npm install
RUN pnpm install --prod=false
ADD front/e2e \
front/tsconfig.json \
front/tslint.json \
front/angular.json \
/tmp/
ADD front/src /tmp/src
###############################################################
## Install sources
###############################################################
FROM dependency_front AS load_sources_front
# generate build
RUN ng build --output-path=dist --configuration=production --base-href=/karusic/ --deploy-url=/karusic/
# JUST to get the vertion of the application and his sha...
COPY \
front/tsconfig.json \
front/tsconfig.node.json \
front/vite.config.mts \
front/index.html \
./
COPY front/public ./public
COPY front/public/icons ./public/icons
COPY front/src ./src
#We are not in prod mode ==> we need to overwrite the production env.
ARG env=front/.env.production
COPY ${env} .env
###############################################################
## Build the sources
###############################################################
FROM load_sources_front AS build_front
# build in bundle mode all the application
RUN pnpm static:build
######################################################################################
##
## Production area:
##
######################################################################################
FROM bellsoft/liberica-openjdk-alpine-musl:latest
FROM bellsoft/liberica-openjdk-alpine:latest
# add wget to manage the health check...
RUN apk add --no-cache wget
#FROM archlinux:base
#RUN pacman -Syu --noconfirm && pacman-db-upgrade
## install package
#RUN pacman -S --noconfirm jdk-openjdk wget
## intall npm
#RUN pacman -S --noconfirm npm
## clean all the caches Need only on the release environment
#RUN pacman -Scc --noconfirm
RUN addgroup -S user \
&& adduser -S user -G user
ENV LANG=C.UTF-8
COPY --from=buildBack /tmp/out/maven/*.jar /application/application.jar
COPY --from=buildFront /tmp/dist /application/front/
WORKDIR /application/
EXPOSE 80
WORKDIR /application/
RUN chown user:user -R /application
CMD ["java", "-Xms64M", "-Xmx1G", "-cp", "/application/application.jar", "org.kar.karusic.WebLauncher"]
# To verify health-check: docker inspect --format "{{json .State.Health }}" YOUR_SERVICE_NAME | jq
HEALTHCHECK --start-period=10s --start-interval=2s --interval=30s --timeout=5s --retries=10 \
CMD wget --no-verbose --tries=1 --spider http://localhost:80/api/health_check || exit 1
CMD ["java", "-Xms64M", "-Xmx1G", "-cp", "/application/application.jar", "org.atriasoft.karusic.WebLauncher"]
COPY --chown=user:user --from=build_back /tmp/out/maven/*.jar /application/application.jar
COPY --chown=user:user --from=build_front /tmp/dist /application/front/
USER user

125
README.md Normal file
View File

@ -0,0 +1,125 @@
Karusic
=======
**K**angaroo **A**nd **R**abbit (m)usic is a simple framework to propose music streaming for personal network
Run in local:
=============
Start tools
-----------
Start the server basic interfaces: (DB(mySQL), Adminer)
```{.bash}
# start the Bdd interface (no big data > 50Mo)
docker compose -f env_dev/docker-compose.yaml up -d
```
Start the Back-end:
-------------------
backend is developed in JAVA
The first step is configuring your JAVA version (or select the JVM with the OS)
```bash
export PATH=$(ls -d --color=never /usr/lib/jvm/java-2*-openjdk)/bin:$PATH
```
Install the dependency:
```bash
mvn install
```
Run the test
```bash
mvn test
```
Install it for external use
```bash
mvn install
```
Execute the local server:
```bash
mvn exec:java@dev-mode
```
Start the Front-end:
--------------------
backend is developed in JAVA
```bash
cd front
pnpm install
pnpm dev
```
Display the result:
-------------------
[show the webpage: http://localhost:4203](http://localhost:4203)
Some other dev tools:
=====================
Format code:
------------
```bash
export PATH=$(ls -d --color=never /usr/lib/jvm/java-2*-openjdk)/bin:$PATH
mvn formatter:format
mvn test
```
Tools in production mode
========================
Changing the Log Level
----------------------
In a production environment, you can adjust the log level to help diagnose bugs more effectively.
The available log levels are:
| **Log Level Tag** | **org.atriasoft.karusic** | **org.kar.archidata** | **other** |
| ----------------- | ------------------- | --------------------- | --------- |
| `prod` | INFO | INFO | INFO |
| `prod-debug` | DEBUG | INFO | INFO |
| `prod-trace` | TRACE | DEBUG | INFO |
| `prod-trace-full` | TRACE | TRACE | INFO |
| `dev` | TRACE | DEBUG | INFO |
Manual set in production:
=========================
Connect on the registry
------------------------
To log-in and log-out from the registry:
```bash
export REGISTRY_ADDRESS=gitea.atria-soft.org
docker login -u <<YOUR_USER_NAME>> ${REGISTRY_ADDRESS}
docker logout ${REGISTRY_ADDRESS}
```
pull the root image of dockers
------------------------------
```bash
docker pull archlinux:base-devel
docker pull bellsoft/liberica-openjdk-alpine:latest
```
Create the version
------------------
Execute in the local folder: (use ```dev``` for development and ```latest``` for production release)
```bash
export TAG_DOCKER=latest
export REGISTRY_ADDRESS=gitea.atria-soft.org
docker build -t ${REGISTRY_ADDRESS}/kangaroo-and-rabbit/karusic:${TAG_DOCKER} .
docker push ${REGISTRY_ADDRESS}/kangaroo-and-rabbit/karusic:${TAG_DOCKER}
```

View File

@ -53,6 +53,9 @@ Checkstyle configuration that checks the sun coding conventions.
<module name="LambdaParameterName"/>
<module name="Regexp"/>
<module name="RegexpSinglelineJava"/>
<module name="UnusedPrivateField">
<property name="ignorePattern" value="LOGGER"/>
</module>
</module>
<module name="BeforeExecutionExclusionFileFilter">
<property name="fileNamePattern" value="module\-info\.java$"/>

View File

@ -1,7 +1,8 @@
FROM maven:3-openjdk-18 AS build
FROM maven:3-openjdk-23 AS build
COPY pom.xml /tmp/
COPY src /tmp/src/
COPY Formatter.xml /tmp/
WORKDIR /tmp/
RUN mvn clean compile assembly:single
@ -17,5 +18,5 @@ WORKDIR /application/
EXPOSE 18080
CMD ["java", "-Xms64M", "-Xmx1G", "-cp", "/application/application.jar", "org.kar.karusic.WebLauncher"]
CMD ["java", "-Xms64M", "-Xmx1G", "-cp", "/application/application.jar", "org.atriasoft.karusic.WebLauncher"]

View File

@ -11,7 +11,7 @@ mvn package
// download all dependency in out/maven/dependency
mvn dependency:copy-dependencies
java -cp out/maven/kar-karusic-0.1.0.jar org.kar.karusic.WebLauncher
java -cp out/maven/kar-karusic-0.1.0.jar org.atriasoft.karusic.WebLauncher
// create a single package jar
@ -19,7 +19,7 @@ mvn clean compile assembly:single
java -cp out/maven/karusic-0.1.0-jar-with-dependencies.jar org.kar.karusic.WebLauncher
java -cp out/maven/karusic-0.1.0-jar-with-dependencies.jar org.atriasoft.karusic.WebLauncher

View File

@ -1,4 +0,0 @@

View File

@ -1,32 +1,42 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.kar</groupId>
<artifactId>karusic</artifactId>
<version>0.1.0</version>
<properties>
<maven.compiler.version>3.1</maven.compiler.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<maven.dependency.version>3.1.1</maven.dependency.version>
</properties>
<repositories>
<repository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
</repository>
</repositories>
<modelVersion>4.0.0</modelVersion>
<groupId>org.atriasoft</groupId>
<artifactId>karusic</artifactId>
<version>1.2.0</version>
<dependencies>
<dependency>
<groupId>kangaroo-and-rabbit</groupId>
<groupId>org.atria-soft</groupId>
<artifactId>archidata</artifactId>
<version>0.6.0</version>
<version>0.30.6</version>
</dependency>
<!-- Loopback of logger JDK logging API to SLF4J -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<artifactId>jul-to-slf4j</artifactId>
<version>2.0.9</version>
</dependency>
<!-- generic logger of SLF4J to console (in color) -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.11</version>
</dependency>
<dependency>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<version>2.12.2</version>
</dependency>
<dependency>
<groupId>org.codehaus.janino</groupId>
<artifactId>janino</artifactId>
<version>3.1.9</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.18.3</version>
</dependency>
<!--
************************************************************
** TEST dependency **
@ -35,15 +45,25 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.1</version>
<version>5.12.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.10.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.12.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.revelc.code.formatter</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<version>2.25.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.6.0</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
@ -63,25 +83,54 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.version}</version>
<version>3.14.0</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<source>21</source>
<target>21</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.4.0</version>
<version>3.2.0</version>
<executions>
<execution>
<id>prod-mode</id>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>org.atriasoft.karusic.WebLauncher</mainClass>
</configuration>
</execution>
<execution>
<id>dev-mode</id>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>org.atriasoft.karusic.WebLauncherLocal</mainClass>
</configuration>
</execution>
<execution>
<id>generate-api</id>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>org.atriasoft.karusic.GenerateApi</mainClass>
</configuration>
</execution>
</executions>
<configuration>
<mainClass>org.kar.karusic.WebLauncher</mainClass>
<mainClass/>
</configuration>
</plugin>
<!-- Create the source bundle -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<version>4.0.0-beta-1</version>
<executions>
<execution>
<id>attach-sources</id>
@ -95,10 +144,12 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<version>3.2.5</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.7.1</version>
<configuration>
<archive>
<manifest>
@ -110,94 +161,21 @@
</descriptorRefs>
</configuration>
</plugin>
<!-- Create coverage -->
<!--
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.10</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>jacoco-check</id>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<element>PACKAGE</element>
<limits>
<limit>
<counter>LINE</counter>
<value>COVEREDRATIO</value>
<minimum>0.50</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
-->
<!-- Java-doc generation for stand-alone site -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
<version>3.3.0</version>
<configuration>
<show>private</show>
<nohelp>true</nohelp>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>exec-application</id>
<phase>package</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>org.kar.karusic.WebLauncher</mainClass>
</configuration>
</plugin>
<!-- Check the style of the code -->
<!--
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<configLocation>CheckStyle.xml</configLocation>
<consoleOutput>true</consoleOutput>
<failOnViolation>true</failOnViolation>
<failsOnError>true</failsOnError>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
</configuration>
</plugin>
<plugin>
<groupId>net.revelc.code.formatter</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<version>2.12.2</version>
<version>2.24.1</version>
<configuration>
<encoding>UTF-8</encoding>
<lineEnding>LF</lineEnding>
@ -221,7 +199,15 @@
</execution>
</executions>
</plugin>
-->
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>4.8.5.0</version>
<configuration>
<includeFilterFile>spotbugs-security-include.xml</includeFilterFile>
<excludeFilterFile>spotbugs-security-exclude.xml</excludeFilterFile>
</configuration>
</plugin>
</plugins>
</build>
<!-- Generate Java-docs As Part Of Project Reports -->
@ -230,7 +216,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
<version>3.3.0</version>
<configuration>
<show>public</show>
</configuration>

258
back/pom.xml.versionsBackup Normal file
View File

@ -0,0 +1,258 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.kar</groupId>
<artifactId>karusic</artifactId>
<version>0.1.0</version>
<properties>
<maven.compiler.version>3.1</maven.compiler.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<maven.dependency.version>3.1.1</maven.dependency.version>
</properties>
<repositories>
<repository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId>
<version>0.14.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.1.0-alpha1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.18.0-rc1</version>
</dependency>
<!--
************************************************************
** TEST dependency **
************************************************************
-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.revelc.code.formatter</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<version>2.24.1</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.5.0</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
<testSourceDirectory>test/src</testSourceDirectory>
<directory>${project.basedir}/out/maven/</directory>
<resources>
<resource>
<directory>src/resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>${basedir}/test/resources</directory>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.version}</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.4.0</version>
<configuration>
<mainClass>org.kar.karusic.WebLauncher</mainClass>
</configuration>
</plugin>
<!-- Create the source bundle -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- junit results -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<!-- Create coverage -->
<!--
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.10</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>jacoco-check</id>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<element>PACKAGE</element>
<limits>
<limit>
<counter>LINE</counter>
<value>COVEREDRATIO</value>
<minimum>0.50</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
-->
<!-- Java-doc generation for stand-alone site -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<show>private</show>
<nohelp>true</nohelp>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>exec-application</id>
<phase>package</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>org.kar.karusic.WebLauncher</mainClass>
</configuration>
</plugin>
<!-- Check the style of the code -->
<plugin>
<groupId>net.revelc.code.formatter</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<version>2.23.0</version>
<configuration>
<encoding>UTF-8</encoding>
<lineEnding>LF</lineEnding>
<configFile>Formatter.xml</configFile>
<directories>
<directory>src/</directory>
<directory>test/src</directory>
</directories>
<includes>
<include>**/*.java</include>
</includes>
<excludes>
<exclude>module-info.java</exclude>
</excludes>
</configuration>
<executions>
<execution>
<goals>
<goal>validate</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>4.8.5.0</version>
<configuration>
<includeFilterFile>spotbugs-security-include.xml</includeFilterFile>
<excludeFilterFile>spotbugs-security-exclude.xml</excludeFilterFile>
<!--<plugins>
<plugin>
<groupId>com.h3xstream.findsecbugs</groupId>
<artifactId>findsecbugs-plugin</artifactId>
<version>1.12.0</version>
</plugin>
</plugins>
-->
</configuration>
</plugin>
</plugins>
</build>
<!-- Generate Java-docs As Part Of Project Reports -->
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<show>public</show>
</configuration>
</plugin>
</plugins>
</reporting>
</project>

View File

@ -1,9 +1,9 @@
org.kar.karideo.dataTmpFolder=/application/data/tmp
org.kar.karideo.dataTmpFolder=/application/data/media
org.kar.karideo.rest.oauth=http://192.168.1.156:21080/oauth/api/
org.kar.karideo.db.host=1992.156.1.156
org.kar.karideo.db.port=20306
org.kar.karideo.db.login=root
org.kar.karideo.db.port=klkhj456gkgtkhjgvkujfhjgkjhgsdfhb3467465fgdhdesfgh
org.kar.karideo.db.name=karideo
org.kar.karideo.address=http://0.0.0.0:18080/karideo/api/
org.atriasoft.karideo.dataTmpFolder=/application/data/tmp
org.atriasoft.karideo.dataTmpFolder=/application/data/media
org.atriasoft.karideo.rest.oauth=http://192.168.1.156:21080/oauth/api/
org.atriasoft.karideo.db.host=1992.156.1.156
org.atriasoft.karideo.db.port=20306
org.atriasoft.karideo.db.login=root
org.atriasoft.karideo.db.port=klkhj456gkgtkhjgvkujfhjgkjhgsdfhb3467465fgdhdesfgh
org.atriasoft.karideo.db.name=karideo
org.atriasoft.karideo.address=http://0.0.0.0:18080/karideo/api/

View File

@ -0,0 +1,27 @@
package org.atriasoft.karusic.CodecBson;
import java.util.UUID;
import org.bson.BsonReader;
import org.bson.BsonWriter;
import org.bson.codecs.Codec;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.EncoderContext;
public class UUIDCodec implements Codec<UUID> {
@Override
public UUID decode(final BsonReader reader, final DecoderContext decoderContext) {
return UUID.fromString(reader.readString());
}
@Override
public void encode(final BsonWriter writer, final UUID value, final EncoderContext encoderContext) {
writer.writeString(value.toString());
}
@Override
public Class<UUID> getEncoderClass() {
return UUID.class;
}
}

View File

@ -0,0 +1,17 @@
package org.atriasoft.karusic;
import org.atriasoft.karusic.migration.Initialization;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class GenerateApi {
private final static Logger LOGGER = LoggerFactory.getLogger(GenerateApi.class);
private GenerateApi() {}
public static void main(final String[] args) throws Exception {
LOGGER.info("Generate API");
Initialization.generateObjects();
LOGGER.info("STOP the REST server.");
}
}

View File

@ -1,36 +1,45 @@
package org.kar.karusic;
package org.atriasoft.karusic;
import java.net.URI;
import java.util.Iterator;
import java.util.TimeZone;
import java.util.logging.LogManager;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriter;
import org.atriasoft.archidata.UpdateJwtPublicKey;
import org.atriasoft.archidata.api.DataResource;
import org.atriasoft.archidata.api.ProxyResource;
import org.atriasoft.archidata.catcher.GenericCatcher;
import org.atriasoft.archidata.db.DbConfig;
import org.atriasoft.archidata.exception.DataAccessException;
import org.atriasoft.archidata.filter.CORSFilter;
import org.atriasoft.archidata.filter.OptionFilter;
import org.atriasoft.archidata.migration.MigrationEngine;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.archidata.tools.ContextGenericTools;
import org.atriasoft.karusic.api.AlbumResource;
import org.atriasoft.karusic.api.ArtistResource;
import org.atriasoft.karusic.api.Front;
import org.atriasoft.karusic.api.GenderResource;
import org.atriasoft.karusic.api.HealthCheck;
import org.atriasoft.karusic.api.PlaylistResource;
import org.atriasoft.karusic.api.TrackResource;
import org.atriasoft.karusic.api.UserResource;
import org.atriasoft.karusic.filter.KarusicAuthenticationFilter;
import org.atriasoft.karusic.migration.Initialization;
import org.atriasoft.karusic.migration.Migration20250427;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.kar.archidata.GlobalConfiguration;
import org.kar.archidata.UpdateJwtPublicKey;
import org.kar.archidata.api.DataResource;
import org.kar.archidata.catcher.ExceptionCatcher;
import org.kar.archidata.catcher.FailExceptionCatcher;
import org.kar.archidata.catcher.InputExceptionCatcher;
import org.kar.archidata.catcher.SystemExceptionCatcher;
import org.kar.archidata.filter.CORSFilter;
import org.kar.archidata.filter.OptionFilter;
import org.kar.archidata.migration.MigrationEngine;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.karusic.api.AlbumResource;
import org.kar.karusic.api.ArtistResource;
import org.kar.karusic.api.Front;
import org.kar.karusic.api.GenderResource;
import org.kar.karusic.api.HealthCheck;
import org.kar.karusic.api.PlaylistResource;
import org.kar.karusic.api.TrackResource;
import org.kar.karusic.api.UserResource;
import org.kar.karusic.filter.KarusicAuthenticationFilter;
import org.kar.karusic.migration.Initialization;
import org.kar.karusic.migration.Migration20231126;
import org.glassfish.jersey.server.validation.ValidationFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;
import jakarta.ws.rs.core.UriBuilder;
@ -40,6 +49,7 @@ public class WebLauncher {
protected HttpServer server = null;
public WebLauncher() {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
ConfigBaseVariable.bdDatabase = "karusic";
}
@ -53,13 +63,17 @@ public class WebLauncher {
WebLauncher.LOGGER.info("Add initialization");
migrationEngine.setInit(new Initialization());
WebLauncher.LOGGER.info("Add migration since last version");
migrationEngine.add(new Migration20231126());
migrationEngine.add(new Migration20250427());
WebLauncher.LOGGER.info("Migrate the DB [START]");
migrationEngine.migrateWaitAdmin(GlobalConfiguration.dbConfig);
migrationEngine.migrateWaitAdmin(new DbConfig());
WebLauncher.LOGGER.info("Migrate the DB [STOP]");
}
public static void main(final String[] args) throws Exception {
// Loop-back of logger JDK logging API to SLF4J
LogManager.getLogManager().reset();
SLF4JBridgeHandler.install();
WebLauncher.LOGGER.info("[START] application wake UP");
final WebLauncher launcher = new WebLauncher();
launcher.migrateDB();
@ -72,7 +86,34 @@ public class WebLauncher {
WebLauncher.LOGGER.info("STOP the REST server:");
}
public void process() throws InterruptedException {
public void plop(final String aaa) {
// List available Image Readers
WebLauncher.LOGGER.trace("Available Image Readers:");
final Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName(aaa);
while (readers.hasNext()) {
final ImageReader reader = readers.next();
WebLauncher.LOGGER.trace("Reader: " + reader.getOriginatingProvider().getDescription(null));
WebLauncher.LOGGER.trace("Reader CN: " + reader.getOriginatingProvider().getPluginClassName());
// ImageIO.deregisterServiceProvider(reader.getOriginatingProvider());
}
// List available Image Writers
WebLauncher.LOGGER.trace("\nAvailable Image Writers:");
final Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(aaa);
while (writers.hasNext()) {
final ImageWriter writer = writers.next();
WebLauncher.LOGGER.trace("Writer: " + writer.getOriginatingProvider().getDescription(null));
WebLauncher.LOGGER.trace("Writer CN: " + writer.getOriginatingProvider().getPluginClassName());
}
}
public void process() throws InterruptedException, DataAccessException {
ImageIO.scanForPlugins();
plop("jpeg");
plop("png");
plop("webmp");
plop("webp");
// ===================================================================
// Configure resources
// ===================================================================
@ -87,10 +128,7 @@ public class WebLauncher {
// global authentication system
rc.register(KarusicAuthenticationFilter.class);
// register exception catcher
rc.register(InputExceptionCatcher.class);
rc.register(SystemExceptionCatcher.class);
rc.register(FailExceptionCatcher.class);
rc.register(ExceptionCatcher.class);
GenericCatcher.addAll(rc);
// add default resource:
rc.register(UserResource.class);
rc.register(AlbumResource.class);
@ -99,22 +137,27 @@ public class WebLauncher {
rc.register(PlaylistResource.class);
rc.register(TrackResource.class);
rc.register(DataResource.class);
rc.register(ProxyResource.class);
rc.register(HealthCheck.class);
rc.register(Front.class);
ContextGenericTools.addJsr310(rc);
// add jackson to be discover when we are ins standalone server
rc.register(JacksonFeature.class);
// enable jersey specific validations (@Valid)
rc.register(ValidationFeature.class);
// enable this to show low level request
//rc.property(LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_SERVER, Level.WARNING.getName());
// rc.property(LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_SERVER, Level.WARNING.getName());
//System.out.println("Connect on the BDD:");
//System.out.println(" getDBHost: '" + ConfigVariable.getDBHost() + "'");
//System.out.println(" getDBPort: '" + ConfigVariable.getDBPort() + "'");
//System.out.println(" getDBLogin: '" + ConfigVariable.getDBLogin() + "'");
//System.out.println(" getDBPassword: '" + ConfigVariable.getDBPassword() + "'");
//System.out.println(" getDBName: '" + ConfigVariable.getDBName() + "'");
System.out.println(" ==> " + GlobalConfiguration.dbConfig);
// System.out.println("Connect on the BDD:");
// System.out.println(" getDBHost: '" + ConfigVariable.getDBHost() + "'");
// System.out.println(" getDBPort: '" + ConfigVariable.getDBPort() + "'");
// System.out.println(" getDBLogin: '" + ConfigVariable.getDBLogin() + "'");
// System.out.println(" getDBPassword: '" + ConfigVariable.getDBPassword() + "'");
// System.out.println(" getDBName: '" + ConfigVariable.getDBName() + "'");
System.out.println(" ==> " + new DbConfig());
System.out.println("OAuth service " + getBaseURI());
this.server = GrizzlyHttpServerFactory.createHttpServer(getBaseURI(), rc);
final HttpServer serverLink = this.server;

View File

@ -0,0 +1,52 @@
package org.atriasoft.karusic;
import java.util.logging.LogManager;
import org.atriasoft.archidata.exception.DataAccessException;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.karusic.migration.Initialization;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;
public class WebLauncherLocal extends WebLauncher {
private static final Logger LOGGER = LoggerFactory.getLogger(WebLauncherLocal.class);
private WebLauncherLocal() {}
public static void main(final String[] args) throws Exception {
// Loop-back of logger JDK logging API to SLF4J
LogManager.getLogManager().reset();
SLF4JBridgeHandler.install();
// Generate the APIs in type-script
Initialization.generateObjects();
final WebLauncherLocal launcher = new WebLauncherLocal();
launcher.process();
LOGGER.info("end-configure the server & wait finish process:");
Thread.currentThread().join();
LOGGER.info("STOP the REST server:");
}
@Override
public void process() throws InterruptedException, DataAccessException {
if (true) {
// for local test:
ConfigBaseVariable.apiAdress = "http://0.0.0.0:19080/karusic/api/";
ConfigBaseVariable.testMode = "true";
ConfigBaseVariable.dbType = "mongo";
}
// Test fail of SSO: ConfigBaseVariable.ssoAdress = null;
try {
super.migrateDB();
} catch (final Exception e) {
e.printStackTrace();
while (true) {
LOGGER.error("============================================================================");
LOGGER.error("== Migration fail ==> waiting intervention of administrator...");
LOGGER.error("============================================================================");
Thread.sleep(60 * 60 * 1000);
}
}
super.process();
}
}

View File

@ -0,0 +1,142 @@
package org.atriasoft.karusic.api;
import java.io.InputStream;
import java.util.List;
import org.atriasoft.archidata.annotation.apiGenerator.ApiInputOptional;
import org.atriasoft.archidata.annotation.apiGenerator.ApiTypeScriptProgress;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.atriasoft.archidata.tools.DataTools;
import org.atriasoft.karusic.model.Album;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.Valid;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
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;
@Path("/album")
@Produces({ MediaType.APPLICATION_JSON })
public class AlbumResource {
private static final Logger LOGGER = LoggerFactory.getLogger(AlbumResource.class);
@GET
@Path("{oid}")
@RolesAllowed("USER")
@Operation(description = "Get a specific Album with his ID")
public Album get(@PathParam("oid") final ObjectId oid) throws Exception {
return DataAccess.get(Album.class, oid);
// return this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id)).first();
}
@GET
@RolesAllowed("USER")
@Operation(description = "Get all the available Albums")
public List<Album> gets() throws Exception {
return DataAccess.gets(Album.class);
// final Query<Album> query = this.morphiaService.getDatastore().find(Album.class);
// return query.stream().toList();
}
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
@Operation(description = "Add an album (when all the data already exist)")
public Album post(@Valid final Album data) throws Exception {
// TODO: how to manage the checker ???
// final Album ret = this.morphiaService.getDatastore().save(data);
// return ret;
/* final MongoCollection<Track> trackCollection = db.getCollection("TTRACLK", Track.class); final InsertOneResult res = trackCollection.insertOne(plop); LOGGER.warn("plpop {}", res); final
* ObjectId ploppppp = res.getInsertedId().asObjectId().getValue(); LOGGER.warn("plpop 2522 {}", res.getInsertedId().asObjectId().getValue()); final Track ret =
* trackCollection.find(Filters.eq("_id", res.getInsertedId().asObjectId().getValue())) .first(); System.out.println("Grade found:\t" + ret); */
return DataAccess.insert(data);
}
@PUT
@Path("{oid}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
@Operation(description = "Update a specific album")
public Album put(@PathParam("oid") final ObjectId oid, @Valid final Album album) throws Exception {
// final Query<Album> query = this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id));
// final UpdateOperations<Album> ops = this.morphiaService.getDatastore().createUpdateOperations(Album.class)
// .set("name", master.getName());
// this.morphiaService.getDatastore().update(query, ops);
// return Response.ok(master).build();
album.oid = oid;
DataAccess.update(album, oid);
return DataAccess.get(Album.class, oid);
}
// @PUT
// @Path("{id}")
// @RolesAllowed("ADMIN")
// @Consumes(MediaType.APPLICATION_JSON)
// @Operation(description = "Update a specific album")
// public Album put(@PathParam("id") final ObjectId oid, final Album album)
// throws Exception {
// final Query<Album> query = this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id));
// final UpdateOperations<Album> ops = this.morphiaService.getDatastore().createUpdateOperations(Album.class)
// .set("name", album.getName());
// this.morphiaService.getDatastore().update(query, ops);
// return Response.ok(album).build();
// }
@DELETE
@Path("{oid}")
@RolesAllowed("ADMIN")
@Operation(description = "Remove a specific album")
public void remove(@PathParam("oid") final ObjectId oid) throws Exception {
DataAccess.delete(Album.class, oid);
// this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id)).delete();
}
/* @POST
* @Path("{id}/track/{trackId}")
* @RolesAllowed("ADMIN")
* @Consumes({ MediaType.MULTIPART_FORM_DATA })
* @Operation(description = "Add a Track on a specific album") public Album addTrack(@PathParam("id") final ObjectId oid, @PathParam("trackId") final Long trackId) throws Exception {
* AddOnManyToMany.removeLink(this.dam, Album.class, id, "track", trackId); return this.dam.get(Album.class, id); } */
@POST
@Path("{oid}/cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@Operation(description = "Add a cover on a specific album")
@ApiTypeScriptProgress
public Album uploadCover(@PathParam("oid") final ObjectId oid, @ApiInputOptional @FormDataParam("uri") final String uri, @ApiInputOptional @FormDataParam("file") final InputStream fileInputStream,
@ApiInputOptional @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) {
DataTools.uploadCoverFromUri(db, Album.class, oid, uri);
} else {
DataTools.uploadCover(db, Album.class, oid, fileInputStream, fileMetaData);
}
return db.get(Album.class, oid);
}
}
@DELETE
@Path("{oid}/cover/{coverId}")
@RolesAllowed("ADMIN")
@Operation(description = "Remove a cover on a specific album")
public Album removeCover(@PathParam("oid") final ObjectId oid, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Album.class, "id", oid, "covers", coverId);
return db.get(Album.class, oid);
}
}
}

View File

@ -0,0 +1,99 @@
package org.atriasoft.karusic.api;
import java.io.InputStream;
import java.util.List;
import org.atriasoft.archidata.annotation.apiGenerator.ApiInputOptional;
import org.atriasoft.archidata.annotation.apiGenerator.ApiTypeScriptProgress;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.atriasoft.archidata.tools.DataTools;
import org.atriasoft.karusic.model.Artist;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.Valid;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
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;
@Path("/artist")
@Produces({ MediaType.APPLICATION_JSON })
public class ArtistResource {
private static final Logger LOGGER = LoggerFactory.getLogger(ArtistResource.class);
@GET
@Path("{oid}")
@RolesAllowed("USER")
public Artist get(@PathParam("oid") final ObjectId oid) throws Exception {
return DataAccess.get(Artist.class, oid);
}
@GET
@RolesAllowed("USER")
public List<Artist> gets() throws Exception {
return DataAccess.gets(Artist.class);
}
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Artist post(@Valid final Artist data) throws Exception {
return DataAccess.insert(data);
}
@PUT
@Path("{oid}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Artist put(@PathParam("oid") final ObjectId oid, @Valid final Artist artist) throws Exception {
artist.oid = oid;
DataAccess.update(artist, oid);
return DataAccess.get(Artist.class, oid);
}
@DELETE
@Path("{oid}")
@RolesAllowed("ADMIN")
public void remove(@PathParam("oid") final ObjectId oid) throws Exception {
DataAccess.delete(Artist.class, oid);
}
@POST
@Path("{oid}/cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@ApiTypeScriptProgress
public Artist uploadCover(@PathParam("oid") final ObjectId oid, @ApiInputOptional @FormDataParam("uri") final String uri,
@ApiInputOptional @FormDataParam("file") final InputStream fileInputStream, @ApiInputOptional @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) {
DataTools.uploadCoverFromUri(db, Artist.class, oid, uri);
} else {
DataTools.uploadCover(db, Artist.class, oid, fileInputStream, fileMetaData);
}
return db.get(Artist.class, oid);
}
}
@DELETE
@Path("{oid}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Artist removeCover(@PathParam("oid") final ObjectId oid, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Artist.class, "id", oid, "covers", coverId);
return db.get(Artist.class, oid);
}
}
}

View File

@ -1,7 +1,7 @@
package org.kar.karusic.api;
package org.atriasoft.karusic.api;
import org.kar.archidata.api.FrontGeneric;
import org.kar.karusic.util.ConfigVariable;
import org.atriasoft.archidata.api.FrontGeneric;
import org.atriasoft.karusic.util.ConfigVariable;
import jakarta.ws.rs.Path;

View File

@ -0,0 +1,99 @@
package org.atriasoft.karusic.api;
import java.io.InputStream;
import java.util.List;
import org.atriasoft.archidata.annotation.apiGenerator.ApiInputOptional;
import org.atriasoft.archidata.annotation.apiGenerator.ApiTypeScriptProgress;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.atriasoft.archidata.tools.DataTools;
import org.atriasoft.karusic.model.Gender;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.Valid;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
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;
@Path("/gender")
@Produces({ MediaType.APPLICATION_JSON })
public class GenderResource {
private static final Logger LOGGER = LoggerFactory.getLogger(GenderResource.class);
@GET
@Path("{oid}")
@RolesAllowed("USER")
public Gender get(@PathParam("oid") final ObjectId oid) throws Exception {
return DataAccess.get(Gender.class, oid);
}
@GET
@RolesAllowed("USER")
public List<Gender> gets() throws Exception {
return DataAccess.gets(Gender.class);
}
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Gender post(@Valid final Gender data) throws Exception {
return DataAccess.insert(data);
}
@PUT
@Path("{oid}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Gender patch(@PathParam("oid") final ObjectId oid, @Valid final Gender gender) throws Exception {
gender.oid = oid;
DataAccess.update(gender, oid);
return DataAccess.get(Gender.class, oid);
}
@DELETE
@Path("{oid}")
@RolesAllowed("ADMIN")
public void remove(@PathParam("oid") final ObjectId oid) throws Exception {
DataAccess.delete(Gender.class, oid);
}
@POST
@Path("{oid}/cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@ApiTypeScriptProgress
public Gender uploadCover(@PathParam("oid") final ObjectId oid, @ApiInputOptional @FormDataParam("uri") final String uri,
@ApiInputOptional @FormDataParam("file") final InputStream fileInputStream, @ApiInputOptional @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) {
DataTools.uploadCoverFromUri(db, Gender.class, oid, uri);
} else {
DataTools.uploadCover(db, Gender.class, oid, fileInputStream, fileMetaData);
}
return db.get(Gender.class, oid);
}
}
@DELETE
@Path("{oid}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Gender removeCover(@PathParam("oid") final ObjectId oid, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Gender.class, "_id", oid, "covers", coverId);
return db.get(Gender.class, oid);
}
}
}

View File

@ -1,8 +1,8 @@
package org.kar.karusic.api;
package org.atriasoft.karusic.api;
import org.kar.archidata.exception.FailException;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.JWTWrapper;
import org.atriasoft.archidata.exception.FailException;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.archidata.tools.JWTWrapper;
import jakarta.annotation.security.PermitAll;
import jakarta.ws.rs.GET;
@ -15,8 +15,8 @@ import jakarta.ws.rs.core.Response;
@Produces(MediaType.APPLICATION_JSON)
public class HealthCheck {
public record HealthResult(
String value) {};
public record HealthResult(String value) {
};
@GET
@PermitAll

View File

@ -0,0 +1,93 @@
package org.atriasoft.karusic.api;
import java.io.InputStream;
import java.util.List;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAsyncType;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.atriasoft.archidata.tools.DataTools;
import org.atriasoft.karusic.model.Playlist;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.Valid;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
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;
@Path("/playlist")
@Produces({ MediaType.APPLICATION_JSON })
public class PlaylistResource {
private static final Logger LOGGER = LoggerFactory.getLogger(PlaylistResource.class);
@GET
@Path("{id}")
@RolesAllowed("USER")
public Playlist get(@PathParam("id") final ObjectId oid) throws Exception {
return DataAccess.get(Playlist.class, oid);
}
@GET
@RolesAllowed("USER")
public List<Playlist> gets() throws Exception {
return DataAccess.gets(Playlist.class);
}
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Playlist post(@Valid final Playlist data) throws Exception {
return DataAccess.insert(data);
}
@PUT
@Path("{oid}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Playlist put(@PathParam("oid") final ObjectId oid, @Valid final Playlist playlist) throws Exception {
playlist.oid = oid;
DataAccess.update(playlist, oid);
return DataAccess.get(Playlist.class, oid);
}
@DELETE
@Path("{oid}")
@RolesAllowed("ADMIN")
public void remove(@PathParam("oid") final ObjectId oid) throws Exception {
DataAccess.delete(Playlist.class, oid);
}
@POST
@Path("{oid}/cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@ApiAsyncType(Playlist.class)
public void uploadCover(@PathParam("oid") final ObjectId oid, @FormDataParam("file") final InputStream fileInputStream, @FormDataParam("file") final FormDataContentDisposition fileMetaData)
throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
DataTools.uploadCover(db, Playlist.class, oid, fileInputStream, fileMetaData);
}
}
@DELETE
@Path("{oid}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Playlist removeCover(@PathParam("oid") final ObjectId oid, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Playlist.class, "id", oid, "covers", coverId);
return DataAccess.get(Playlist.class, oid);
}
}
}

View File

@ -0,0 +1,189 @@
package org.atriasoft.karusic.api;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAsyncType;
import org.atriasoft.archidata.annotation.apiGenerator.ApiInputOptional;
import org.atriasoft.archidata.annotation.apiGenerator.ApiTypeScriptProgress;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.tools.DataTools;
import org.atriasoft.karusic.model.Track;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.Valid;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
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;
@Path("/track")
@Produces({ MediaType.APPLICATION_JSON })
public class TrackResource {
private static final Logger LOGGER = LoggerFactory.getLogger(TrackResource.class);
@GET
@Path("{oid}")
@RolesAllowed("USER")
public Track get(@PathParam("oid") final ObjectId oid) throws Exception {
return DataAccess.get(Track.class, oid);
}
@GET
@RolesAllowed("USER")
public List<Track> gets() throws Exception {
return DataAccess.gets(Track.class);
}
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Track post(@Valid final Track data) throws Exception {
return DataAccess.insert(data);
}
@PUT
@Path("{oid}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Track put(@PathParam("oid") final ObjectId oid, @Valid final Track track) throws Exception {
track.oid = oid;
DataAccess.update(track, oid);
return DataAccess.get(Track.class, oid);
}
@DELETE
@Path("{oid}")
@RolesAllowed("ADMIN")
public void remove(@PathParam("oid") final ObjectId oid) throws Exception {
DataAccess.delete(Track.class, oid);
}
@POST
@Path("{oid}/cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@ApiTypeScriptProgress
public Track uploadCover(@PathParam("oid") final ObjectId oid, @FormDataParam("uri") final String uri, @FormDataParam("file") final InputStream fileInputStream,
@FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) {
DataTools.uploadCoverFromUri(db, Track.class, oid, uri);
} else {
DataTools.uploadCover(db, Track.class, oid, fileInputStream, fileMetaData);
}
return DataAccess.get(Track.class, oid);
}
}
@DELETE
@Path("{oid}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Track removeCover(@PathParam("oid") final ObjectId oid, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Track.class, "_id", oid, "covers", coverId);
return db.get(Track.class, oid);
}
}
@POST
@Path("upload/")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@ApiAsyncType(Track.class)
@ApiTypeScriptProgress
public Response uploadTrack( //
@FormDataParam("title") String title, //
@ApiInputOptional @ApiAsyncType(ObjectId.class) @FormDataParam("genderId") String genderId, //
@ApiInputOptional @ApiAsyncType(ObjectId.class) @FormDataParam("artistId") String artistId, //
@ApiInputOptional @ApiAsyncType(ObjectId.class) @FormDataParam("albumId") String albumId, //
@ApiInputOptional @ApiAsyncType(Long.class) @FormDataParam("trackId") String trackId, //
@FormDataParam("file") final InputStream fileInputStream, //
@FormDataParam("file") final FormDataContentDisposition fileMetaData //
) {
try (DBAccess db = DBAccess.createInterface()) {
// correct input string stream :
trackId = DataTools.multipartCorrection(trackId);
albumId = DataTools.multipartCorrection(albumId);
artistId = DataTools.multipartCorrection(artistId);
genderId = DataTools.multipartCorrection(genderId);
title = DataTools.multipartCorrection(title);
// public NodeSmall uploadFile(final FormDataMultiPart form) {
LOGGER.info("Upload media file: " + fileMetaData);
LOGGER.info(" > genderId: " + genderId);
LOGGER.info(" > artistId: " + artistId);
LOGGER.info(" > albumId: " + albumId);
LOGGER.info(" > trackId: " + trackId);
LOGGER.info(" > title: " + title);
LOGGER.info(" > fileInputStream: " + fileInputStream);
LOGGER.info(" > fileMetaData: " + fileMetaData);
/* if (typeId == null) { return Response.status(406). entity("Missing Input 'type'"). type("text/plain"). build(); } */
final long tmpUID = DataTools.getTmpDataId();
final String sha512 = DataTools.saveTemporaryFile(fileInputStream, tmpUID);
Data data = DataTools.getWithSha512(db, sha512);
if (data == null) {
LOGGER.info("Need to add the data in the BDD ... ");
try {
data = DataTools.createNewData(db, tmpUID, fileMetaData.getFileName(), sha512);
} catch (final IOException ex) {
DataTools.removeTemporaryFile(tmpUID);
ex.printStackTrace();
return Response.notModified("can not create input media").build();
} catch (final SQLException ex) {
ex.printStackTrace();
DataTools.removeTemporaryFile(tmpUID);
return Response.notModified("Error in SQL insertion ...").build();
}
} else if (data.deleted) {
LOGGER.info("Data already exist but deleted");
DataTools.undelete(db, data.oid);
data.deleted = false;
} else {
LOGGER.info("Data already exist ... all good");
}
LOGGER.info("add media");
Track trackElem = new Track();
trackElem.name = title;
trackElem.track = trackId != null ? Long.parseLong(trackId) : null;
trackElem.albumId = albumId != null ? new ObjectId(albumId) : null;
trackElem.genderId = genderId != null ? new ObjectId(genderId) : null;
trackElem.dataId = data.oid;
// Now list of artist has an internal management:
if (artistId != null) {
trackElem.artists = new ArrayList<>();
trackElem.artists.add(artistId != null ? new ObjectId(artistId) : null);
}
// TODO: maybe validate here ....
trackElem = DataAccess.insert(trackElem);
/* Old mode of artist insertion (removed due to the slowlest request of getting value if (artistElem != null) { this.dam.addLink(Track.class, trackElem.id, "artist", artistElem.id); } */
return Response.ok(trackElem).build();
} catch (final Exception ex) {
LOGGER.info("Catch an unexpected error ... {}", ex.getMessage());
ex.printStackTrace();
return Response.status(417).entity("Back-end error : " + ex.getMessage()).type("text/plain").build();
}
}
}

View File

@ -1,10 +1,13 @@
package org.kar.karusic.api;
package org.atriasoft.karusic.api;
import java.util.List;
import java.util.Map;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.filter.GenericContext;
import org.kar.karusic.model.UserKarusic;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.filter.GenericContext;
import org.atriasoft.karusic.api.UserResourceModel.PartRight;
import org.atriasoft.karusic.api.UserResourceModel.UserMe;
import org.atriasoft.karusic.model.UserKarusic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -20,9 +23,9 @@ import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.SecurityContext;
@Path("/users")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces(MediaType.APPLICATION_JSON)
public class UserResource {
final Logger logger = LoggerFactory.getLogger(UserResource.class);
private static final Logger LOGGER = LoggerFactory.getLogger(UserResource.class);
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UserOut {
@ -41,8 +44,8 @@ public class UserResource {
// curl http://localhost:9993/api/users
@GET
@RolesAllowed("ADMIN")
public List<UserKarusic> getUsers() {
System.out.println("getUsers");
public List<UserKarusic> gets() {
LOGGER.info("getUsers");
try {
return DataAccess.gets(UserKarusic.class);
} catch (final Exception e) {
@ -56,12 +59,12 @@ public class UserResource {
@GET
@Path("{id}")
@RolesAllowed("ADMIN")
public UserKarusic getUsers(@Context final SecurityContext sc, @PathParam("id") final long userId) {
System.out.println("getUser " + userId);
public UserKarusic get(@Context final SecurityContext sc, @PathParam("id") final long userId) {
LOGGER.info("getUser {}", userId);
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
System.out.println("===================================================");
System.out.println("== USER ? " + gc.userByToken.name);
System.out.println("===================================================");
LOGGER.info("===================================================");
LOGGER.info("== USER {} ", gc.userByToken.name);
LOGGER.info("===================================================");
try {
return DataAccess.get(UserKarusic.class, userId);
} catch (final Exception e) {
@ -74,10 +77,15 @@ public class UserResource {
@GET
@Path("me")
@RolesAllowed("USER")
public UserOut getMe(@Context final SecurityContext sc) {
this.logger.debug("getMe()");
public UserMe getMe(@Context final SecurityContext sc) {
LOGGER.debug("getMe()");
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
this.logger.debug("== USER ? {}", gc.userByToken);
return new UserOut(gc.userByToken.id, gc.userByToken.name);
LOGGER.debug("== USER ? {}", gc.userByToken);
return new UserMe(gc.userByToken.id, gc.userByToken.name, //
Map.of(gc.userByToken.name, //
Map.of("admin", PartRight.READ_WRITE, //
"user", PartRight.READ_WRITE), //
"karusic", //
Map.of("user", PartRight.READ)));
}
}

View File

@ -0,0 +1,9 @@
package org.atriasoft.karusic.api.UserResourceModel;
import java.util.HashMap;
public class ModuleAuthorizations extends HashMap<String, PartRight> {
private static final long serialVersionUID = 1L;
public ModuleAuthorizations() {}
}

View File

@ -0,0 +1,29 @@
package org.atriasoft.karusic.api.UserResourceModel;
import com.fasterxml.jackson.annotation.JsonValue;
public enum PartRight {
READ(1), //
WRITE(2), //
READ_WRITE(3);
private final int value;
PartRight(final int value) {
this.value = value;
}
@JsonValue
public int getValue() {
return this.value;
}
public static PartRight fromValue(final int value) {
for (final PartRight species : PartRight.values()) {
if (species.getValue() == value) {
return species;
}
}
throw new IllegalArgumentException("PartRight: Unknown value: " + value);
}
}

View File

@ -0,0 +1,21 @@
package org.atriasoft.karusic.api.UserResourceModel;
import java.util.Map;
import io.swagger.v3.oas.annotations.media.Schema;
public class UserMe {
public long id;
public String login;
@Schema(description = "Map<EntityName, Map<PartName, Right>>")
public Map<String, Map<String, PartRight>> rights;
public UserMe() {}
public UserMe(final long id, final String login, final Map<String, Map<String, PartRight>> rights) {
this.id = id;
this.login = login;
this.rights = rights;
}
}

View File

@ -1,6 +1,6 @@
package org.kar.karusic.filter;
package org.atriasoft.karusic.filter;
import org.kar.archidata.filter.AuthenticationFilter;
import org.atriasoft.archidata.filter.AuthenticationFilter;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.ext.Provider;
@ -16,7 +16,7 @@ import jakarta.annotation.Priority;
public class KarusicAuthenticationFilter extends AuthenticationFilter {
final Logger logger = LoggerFactory.getLogger(KarusicAuthenticationFilter.class);
public KarusicAuthenticationFilter() {
public KarusicAuthenticationFilter() {
super("karusic");
}

View File

@ -0,0 +1,112 @@
package org.atriasoft.karusic.migration;
import java.util.List;
import org.atriasoft.archidata.api.DataResource;
import org.atriasoft.archidata.api.ProxyResource;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.externalRestApi.AnalyzeApi;
import org.atriasoft.archidata.externalRestApi.TsGenerateApi;
import org.atriasoft.archidata.filter.PartRight;
import org.atriasoft.archidata.migration.MigrationSqlStep;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.User;
import org.atriasoft.archidata.model.token.JwtToken;
import org.atriasoft.karusic.api.AlbumResource;
import org.atriasoft.karusic.api.ArtistResource;
import org.atriasoft.karusic.api.Front;
import org.atriasoft.karusic.api.GenderResource;
import org.atriasoft.karusic.api.HealthCheck;
import org.atriasoft.karusic.api.PlaylistResource;
import org.atriasoft.karusic.api.TrackResource;
import org.atriasoft.karusic.api.UserResource;
import org.atriasoft.karusic.model.Album;
import org.atriasoft.karusic.model.Artist;
import org.atriasoft.karusic.model.Gender;
import org.atriasoft.karusic.model.Playlist;
import org.atriasoft.karusic.model.Track;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Initialization extends MigrationSqlStep {
private static final Logger LOGGER = LoggerFactory.getLogger(Initialization.class);
public static final int KARSO_INITIALISATION_ID = 1;
public static final List<Class<?>> CLASSES_BASE = List.of(Album.class, Artist.class, Data.class, Gender.class, Playlist.class, Track.class, User.class);
@Override
public String getName() {
return "Initialization";
}
public static void generateObjects() throws Exception {
LOGGER.info("Generate APIs");
final List<Class<?>> listOfResources = List.of(AlbumResource.class, ArtistResource.class, Front.class, GenderResource.class, HealthCheck.class, PlaylistResource.class, UserResource.class,
TrackResource.class, DataResource.class, ProxyResource.class);
final AnalyzeApi api = new AnalyzeApi();
api.addAllApi(listOfResources);
api.addModel(JwtToken.class);
api.addModel(PartRight.class);
TsGenerateApi.generateApi(api, "../front/src/back-api/");
LOGGER.info("Generate APIs (DONE)");
}
@Override
public void generateStep() throws Exception {
for (final Class<?> clazz : CLASSES_BASE) {
addClass(clazz);
}
addAction((final DBAccess da) -> {
final List<Gender> data = List.of(//
new Gender("Variété française"), //
new Gender("Pop"), //
new Gender("inconnue"), //
new Gender("Disco"), //
new Gender("Enfants"), //
new Gender("Portugaise"), //
new Gender("Apprentissage"), //
new Gender("Blues"), //
new Gender("Jazz"), //
new Gender("Chanson Noël"), //
new Gender("DubStep"), //
new Gender("Rap français"), //
new Gender("Classique"), //
new Gender("Rock"), //
new Gender("Electro"), //
new Gender("Celtique"), //
new Gender("Country"), //
new Gender("Variété Québéquoise"), //
new Gender("Médiéval"), //
new Gender("Variété Italienne"), //
new Gender("Comédie Musicale"), //
new Gender("Vianney"), //
new Gender("Bande Original"), //
new Gender("Bande Originale"), //
new Gender("Variété Belge"), //
new Gender("Gospel"));
da.insertMultiple(data);
});
}
public static void dropAll(final DBAccess da) {
for (final Class<?> element : CLASSES_BASE) {
try {
da.drop(element);
} catch (final Exception ex) {
LOGGER.error("Fail to drop table !!!!!!");
ex.printStackTrace();
}
}
}
public static void cleanAll(final DBAccess da) {
for (final Class<?> element : CLASSES_BASE) {
try {
da.cleanAll(element);
} catch (final Exception ex) {
LOGGER.error("Fail to clean table !!!!!!");
ex.printStackTrace();
}
}
}
}

View File

@ -0,0 +1,146 @@
package org.atriasoft.karusic.migration;
import java.util.ArrayList;
import java.util.List;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.options.AccessDeletedItems;
import org.atriasoft.archidata.dataAccess.options.DirectData;
import org.atriasoft.archidata.dataAccess.options.ReadAllColumn;
import org.atriasoft.archidata.db.DbConfig;
import org.atriasoft.archidata.migration.MigrationSqlStep;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.karusic.model.Album;
import org.atriasoft.karusic.model.Artist;
import org.atriasoft.karusic.model.Gender;
import org.atriasoft.karusic.model.Track;
import org.atriasoft.karusic.modelOld.AlbumOld;
import org.atriasoft.karusic.modelOld.ArtistOld;
import org.atriasoft.karusic.modelOld.GenderOld;
import org.atriasoft.karusic.modelOld.TrackOld;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Migration20250427 extends MigrationSqlStep {
private static final Logger LOGGER = LoggerFactory.getLogger(Migration20250427.class);
public static final int KARSO_INITIALISATION_ID = 1;
@Override
public String getName() {
return "migration-2025-04-27: Migrate to MongoDB";
}
public static ObjectId getElementArtist(final List<ArtistOld> datas, final Long id) throws Exception {
if (id == null) {
return null;
}
for (final var elem : datas) {
if (elem.id.equals(id)) {
return elem.getOid();
}
}
throw new Exception("Does not exist");
}
public static ObjectId getElementAlbum(final List<AlbumOld> datas, final Long id) throws Exception {
if (id == null) {
return null;
}
for (final var elem : datas) {
if (elem.id.equals(id)) {
return elem.getOid();
}
}
throw new Exception("Does not exist");
}
public static ObjectId getElementGender(final List<GenderOld> datas, final Long id) throws Exception {
if (id == null) {
return null;
}
for (final var elem : datas) {
if (elem.id.equals(id)) {
return elem.getOid();
}
}
throw new Exception("Does not exist");
}
@Override
public void generateStep() throws Exception {
addAction((final DBAccess daMongo) -> {
// Create the previous connection on SQL:
final DbConfig configSQL = new DbConfig("mysql", "db", (short) 3306, ConfigBaseVariable.getDBLogin(), ConfigBaseVariable.getDBPassword(), ConfigBaseVariable.getDBName(),
ConfigBaseVariable.getDBKeepConnected(), List.of(ConfigBaseVariable.getBbInterfacesClasses()));
try (final DBAccess daSQL = DBAccess.createInterface(configSQL)) {
final List<Data> allData = daSQL.gets(Data.class, new ReadAllColumn(), new AccessDeletedItems());
final List<AlbumOld> allOldAlbums = daSQL.gets(AlbumOld.class, new ReadAllColumn(), new AccessDeletedItems());
final List<ArtistOld> allOldArtist = daSQL.gets(ArtistOld.class, new ReadAllColumn(), new AccessDeletedItems());
final List<GenderOld> allOldGender = daSQL.gets(GenderOld.class, new ReadAllColumn(), new AccessDeletedItems());
final List<TrackOld> allTOldrack = daSQL.gets(TrackOld.class, new ReadAllColumn(), new AccessDeletedItems());
for (final Data elem : allData) {
daMongo.insert(elem, new DirectData());
}
for (final AlbumOld elem : allOldAlbums) {
final Album tmp = new Album();
tmp.oid = elem.getOid();
tmp.deleted = elem.deleted;
tmp.updatedAt = elem.updatedAt;
tmp.createdAt = elem.createdAt;
tmp.name = elem.name;
tmp.description = elem.description;
tmp.covers = elem.covers;
daMongo.insert(tmp, new DirectData());
}
for (final ArtistOld elem : allOldArtist) {
final Artist tmp = new Artist();
tmp.oid = elem.getOid();
tmp.deleted = elem.deleted;
tmp.updatedAt = elem.updatedAt;
tmp.createdAt = elem.createdAt;
tmp.name = elem.name;
tmp.description = elem.description;
tmp.covers = elem.covers;
tmp.firstName = elem.firstName;
tmp.birth = elem.birth;
tmp.death = elem.death;
daMongo.insert(tmp, new DirectData());
}
for (final GenderOld elem : allOldGender) {
final Gender tmp = new Gender();
tmp.oid = elem.getOid();
tmp.deleted = elem.deleted;
tmp.updatedAt = elem.updatedAt;
tmp.createdAt = elem.createdAt;
tmp.name = elem.name;
tmp.description = elem.description;
tmp.covers = elem.covers;
daMongo.insert(tmp, new DirectData());
}
for (final TrackOld elem : allTOldrack) {
final Track tmp = new Track();
tmp.oid = elem.getOid();
tmp.deleted = elem.deleted;
tmp.updatedAt = elem.updatedAt;
tmp.createdAt = elem.createdAt;
tmp.name = elem.name;
tmp.description = elem.description;
tmp.covers = elem.covers;
tmp.genderId = getElementGender(allOldGender, elem.genderId);
tmp.albumId = getElementAlbum(allOldAlbums, elem.albumId);
tmp.track = elem.track;
tmp.dataId = elem.dataId;
tmp.artists = new ArrayList<>();
for (final Long artistId : elem.artists) {
tmp.artists.add(getElementArtist(allOldArtist, artistId));
}
daMongo.insert(tmp, new DirectData());
}
}
});
}
}

View File

@ -0,0 +1,18 @@
package org.atriasoft.karusic.migration.model;
import java.util.List;
import java.util.UUID;
import org.bson.types.ObjectId;
import org.atriasoft.archidata.annotation.DataJson;
import jakarta.persistence.Id;
public class CoverConversion {
@Id
public Long id = null;
@DataJson
public List<UUID> covers = null;
@DataJson
public List<ObjectId> covers_oid = null;
}

View File

@ -0,0 +1,14 @@
package org.atriasoft.karusic.migration.model;
import java.util.UUID;
import org.bson.types.ObjectId;
import jakarta.persistence.Id;
public class MediaConversion {
@Id
public Long id = null;
public UUID dataId = null;
public ObjectId dataOid = null;
}

View File

@ -0,0 +1,13 @@
package org.atriasoft.karusic.migration.model;
import java.util.UUID;
import org.bson.types.ObjectId;
import jakarta.persistence.Id;
public class OIDConversion {
@Id
public UUID uuid = null;
public ObjectId _id = null;
}

View File

@ -0,0 +1,44 @@
package org.atriasoft.karusic.model;
import java.util.Date;
import java.util.List;
import org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.OIDGenericDataSoftDelete;
import org.bson.types.ObjectId;
import org.hibernate.validator.constraints.UniqueElements;
import com.fasterxml.jackson.annotation.JsonInclude;
import dev.morphia.annotations.Entity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@Entity()
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
@ApiGenerationMode(create = true, update = true)
public class Album extends OIDGenericDataSoftDelete {
@Column(length = 256)
@Size(min = 1, max = 256)
public String name = null;
@Column(length = 0)
@Size(min = 0, max = 8192)
public String description = null;
@Schema(description = "List of Id of the specific covers")
@Nullable
@CollectionNotEmpty
@UniqueElements
@ApiAccessLimitation(readable = true, creatable = false, updatable = false)
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
public Date publication;
}

View File

@ -0,0 +1,56 @@
package org.atriasoft.karusic.model;
import java.util.Date;
import java.util.List;
import org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.OIDGenericDataSoftDelete;
import org.bson.types.ObjectId;
import org.hibernate.validator.constraints.UniqueElements;
import com.fasterxml.jackson.annotation.JsonInclude;
import dev.morphia.annotations.Entity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@Entity()
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
@ApiGenerationMode(create = true, update = true)
public class Artist extends OIDGenericDataSoftDelete {
@Column(length = 256)
@Size(min = 1, max = 256)
public String name = null;
@Column(length = 0)
@Size(min = 0, max = 8192)
public String description = null;
@Schema(description = "List of Id of the specific covers")
@Nullable
@CollectionNotEmpty
@UniqueElements
@ApiAccessLimitation(readable = true, creatable = false, updatable = false)
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
@Column(length = 256)
@Size(min = 1, max = 256)
public String firstName = null;
@Column(length = 256)
@Size(min = 1, max = 256)
public String surname = null;
public Date birth = null;
public Date death = null;
@Override
public String toString() {
return "Artist [id=" + this.oid + ", name=" + this.name + ", description=" + this.description + ", covers=" + this.covers + ", firstName=" + this.firstName + ", surname=" + this.surname
+ ", birth=" + this.birth + ", death=" + this.death + "]";
}
}

View File

@ -0,0 +1,65 @@
package org.atriasoft.karusic.model;
/*
CREATE TABLE `node` (
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
`deleted` BOOLEAN NOT NULL DEFAULT false,
`create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created',
`modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update',
`type` enum("TYPE", "UNIVERS", "SERIE", "SAISON", "MEDIA") NOT NULL DEFAULT 'TYPE',
`name` TEXT COLLATE 'utf8_general_ci' NOT NULL,
`description` TEXT COLLATE 'utf8_general_ci',
`parent_id` bigint
) AUTO_INCREMENT=10;
*/
import java.util.List;
import org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.OIDGenericDataSoftDelete;
import org.bson.types.ObjectId;
import org.hibernate.validator.constraints.UniqueElements;
import com.fasterxml.jackson.annotation.JsonInclude;
import dev.morphia.annotations.Entity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@Entity()
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
@ApiGenerationMode(create = true, update = true)
public class Gender extends OIDGenericDataSoftDelete {
@Column(length = 256)
@Size(min = 1, max = 256)
public String name = null;
@Column(length = 0)
@Size(min = 0, max = 8192)
public String description = null;
@Schema(description = "List of Id of the specific covers")
@Nullable
@CollectionNotEmpty
@UniqueElements
@ApiAccessLimitation(readable = true, creatable = false, updatable = false)
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
public Gender() {}
public Gender(final String name) {
this.name = name;
}
public Gender(final ObjectId oid, final String name) {
this.oid = oid;
this.name = name;
}
}

View File

@ -0,0 +1,54 @@
package org.atriasoft.karusic.model;
/*
CREATE TABLE `node` (
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
`deleted` BOOLEAN NOT NULL DEFAULT false,
`create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created',
`modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update',
`type` enum("TYPE", "UNIVERS", "SERIE", "SAISON", "MEDIA") NOT NULL DEFAULT 'TYPE',
`name` TEXT COLLATE 'utf8_general_ci' NOT NULL,
`description` TEXT COLLATE 'utf8_general_ci',
`parent_id` bigint
) AUTO_INCREMENT=10;
*/
import java.util.List;
import org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.OIDGenericDataSoftDelete;
import org.bson.types.ObjectId;
import org.hibernate.validator.constraints.UniqueElements;
import com.fasterxml.jackson.annotation.JsonInclude;
import dev.morphia.annotations.Entity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@Entity()
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
@ApiGenerationMode(create = true, update = true)
public class Playlist extends OIDGenericDataSoftDelete {
@Column(length = 256)
@Size(min = 1, max = 256)
public String name = null;
@Column(length = 0)
@Size(min = 0, max = 8192)
public String description = null;
@Schema(description = "List of Id of the specific covers")
@Nullable
@CollectionNotEmpty
@UniqueElements
@ApiAccessLimitation(readable = true, creatable = false, updatable = false)
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
public List<@CheckForeignKey(target = Track.class) @NotNull ObjectId> tracks = null;
}

View File

@ -0,0 +1,10 @@
package org.atriasoft.karusic.model;
public enum State {
// User has remove his account
REMOVED,
// User has been blocked his account
BLOCKED,
// generic user
USER
}

View File

@ -0,0 +1,71 @@
package org.atriasoft.karusic.model;
/*
CREATE TABLE `node` (
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
`deleted` BOOLEAN NOT NULL DEFAULT false,
`create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created',
`modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update',
`type` enum("TYPE", "UNIVERS", "SERIE", "SAISON", "MEDIA") NOT NULL DEFAULT 'TYPE',
`name` TEXT COLLATE 'utf8_general_ci' NOT NULL,
`description` TEXT COLLATE 'utf8_general_ci',
`parent_id` bigint
) AUTO_INCREMENT=10;
*/
import java.util.List;
import org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.OIDGenericDataSoftDelete;
import org.bson.types.ObjectId;
import org.hibernate.validator.constraints.UniqueElements;
import com.fasterxml.jackson.annotation.JsonInclude;
import dev.morphia.annotations.Entity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.PositiveOrZero;
import jakarta.validation.constraints.Size;
@Entity()
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
@ApiGenerationMode(create = true, update = true)
public class Track extends OIDGenericDataSoftDelete {
@Column(length = 256)
@Size(min = 1, max = 256)
public String name = null;
@Column(length = 0)
@Size(min = 0, max = 8192)
public String description = null;
@Schema(description = "List of Id of the specific covers")
@Nullable
@CollectionNotEmpty
@UniqueElements
@ApiAccessLimitation(readable = true, creatable = false, updatable = false)
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
@CheckForeignKey(target = Gender.class)
public ObjectId genderId = null;
@CheckForeignKey(target = Album.class)
public ObjectId albumId = null;
@PositiveOrZero
public Long track = null;
@CheckForeignKey(target = Data.class)
public ObjectId dataId = null;
@Column(length = 0)
public List<@CheckForeignKey(target = Artist.class) @NotNull ObjectId> artists = null;
@Override
public String toString() {
return "Track [oid=" + this.oid + ", deleted=" + this.deleted + ", createdAt=" + this.createdAt + ", updatedAt=" + this.updatedAt + ", name=" + this.name + ", description=" + this.description
+ ", covers=" + this.covers + ", genderId=" + this.genderId + ", albumId=" + this.albumId + ", track=" + this.track + ", dataId=" + this.dataId + ", artists=" + this.artists + "]";
}
}

View File

@ -1,7 +1,7 @@
package org.kar.karusic.model;
package org.atriasoft.karusic.model;
import org.kar.archidata.annotation.DataIfNotExists;
import org.kar.archidata.model.User;
import org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.model.User;
import com.fasterxml.jackson.annotation.JsonInclude;

View File

@ -0,0 +1,32 @@
package org.atriasoft.karusic.modelOld;
import java.util.Date;
import java.util.List;
import org.atriasoft.archidata.annotation.DataJson;
import org.atriasoft.archidata.model.GenericDataSoftDelete;
import org.bson.types.ObjectId;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
import jakarta.persistence.Table;
@Table(name = "album")
public class AlbumOld extends GenericDataSoftDelete {
@Column(length = 256)
public String name = null;
@Column(length = 0)
public String description = null;
@Schema(description = "List of Id of the specific covers")
@DataJson()
public List<ObjectId> covers = null;
public Date publication;
@Column(nullable = true)
private final ObjectId oid = new ObjectId();
public ObjectId getOid() {
return this.oid;
}
}

View File

@ -0,0 +1,34 @@
package org.atriasoft.karusic.modelOld;
import java.util.Date;
import java.util.List;
import org.atriasoft.archidata.annotation.DataJson;
import org.atriasoft.archidata.model.GenericDataSoftDelete;
import org.bson.types.ObjectId;
import jakarta.persistence.Column;
import jakarta.persistence.Table;
@Table(name = "artist")
public class ArtistOld extends GenericDataSoftDelete {
@Column(length = 256)
public String name = null;
@Column(length = 0)
public String description = null;
@DataJson()
public List<ObjectId> covers = null;
@Column(length = 256)
public String firstName = null;
@Column(length = 256)
public String surname = null;
public Date birth = null;
public Date death = null;
@Column(nullable = true)
private final ObjectId oid = new ObjectId();
public ObjectId getOid() {
return this.oid;
}
}

View File

@ -0,0 +1,53 @@
package org.atriasoft.karusic.modelOld;
/*
CREATE TABLE `node` (
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
`deleted` BOOLEAN NOT NULL DEFAULT false,
`create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created',
`modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update',
`type` enum("TYPE", "UNIVERS", "SERIE", "SAISON", "MEDIA") NOT NULL DEFAULT 'TYPE',
`name` TEXT COLLATE 'utf8_general_ci' NOT NULL,
`description` TEXT COLLATE 'utf8_general_ci',
`parent_id` bigint
) AUTO_INCREMENT=10;
*/
import java.util.List;
import org.atriasoft.archidata.annotation.DataJson;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.GenericDataSoftDelete;
import org.bson.types.ObjectId;
import jakarta.persistence.Column;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
@Table(name = "gender")
public class GenderOld extends GenericDataSoftDelete {
@Column(length = 256)
public String name = null;
@Column(length = 0)
public String description = null;
@DataJson()
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
public GenderOld() {}
public GenderOld(final String name) {
this.name = name;
}
public GenderOld(final Long id, final String name) {
this.id = id;
this.name = name;
}
@Column(nullable = true)
private final ObjectId oid = new ObjectId();
public ObjectId getOid() {
return this.oid;
}
}

View File

@ -0,0 +1,48 @@
package org.atriasoft.karusic.modelOld;
/*
CREATE TABLE `node` (
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
`deleted` BOOLEAN NOT NULL DEFAULT false,
`create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created',
`modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update',
`type` enum("TYPE", "UNIVERS", "SERIE", "SAISON", "MEDIA") NOT NULL DEFAULT 'TYPE',
`name` TEXT COLLATE 'utf8_general_ci' NOT NULL,
`description` TEXT COLLATE 'utf8_general_ci',
`parent_id` bigint
) AUTO_INCREMENT=10;
*/
import java.util.List;
import org.atriasoft.archidata.annotation.DataJson;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.GenericDataSoftDelete;
import org.bson.types.ObjectId;
import jakarta.persistence.Column;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
@Table(name = "track")
public class TrackOld extends GenericDataSoftDelete {
@Column(length = 256)
public String name = null;
@Column(length = 0)
public String description = null;
@DataJson()
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
public Long genderId = null;
public Long albumId = null;
public Long track = null;
public ObjectId dataId = null;
@DataJson
public List<Long> artists = null;
@Column(nullable = true)
private final ObjectId oid = new ObjectId();
public ObjectId getOid() {
return this.oid;
}
}

View File

@ -0,0 +1,14 @@
package org.atriasoft.karusic.util;
public class ConfigVariable {
public static final String BASE_NAME = "ORG_KARUSIC_";
public static String getFrontFolder() {
String out = System.getenv(BASE_NAME + "FRONT_FOLDER");
if (out == null) {
return "/application/front";
}
return out;
}
}

View File

@ -1,41 +0,0 @@
package org.kar.karusic;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class WebLauncherLocal extends WebLauncher {
final Logger logger = LoggerFactory.getLogger(WebLauncherLocal.class);
private WebLauncherLocal() {}
public static void main(final String[] args) throws InterruptedException {
final WebLauncherLocal launcher = new WebLauncherLocal();
launcher.process();
launcher.logger.info("end-configure the server & wait finish process:");
Thread.currentThread().join();
launcher.logger.info("STOP the REST server:");
}
@Override
public void process() throws InterruptedException {
if (true) {
// for local test:
ConfigBaseVariable.apiAdress = "http://0.0.0.0:19080/karusic/api/";
//ConfigBaseVariable.ssoAdress = "https://atria-soft.org/karso/api/";
ConfigBaseVariable.dbPort = "3906";
}
try {
super.migrateDB();
} catch (final Exception e) {
e.printStackTrace();
while (true) {
LOGGER.error("============================================================================");
LOGGER.error("== Migration fail ==> waiting intervention of administrator...");
LOGGER.error("============================================================================");
Thread.sleep(60 * 60 * 1000);
}
}
super.process();
}
}

View File

@ -1,99 +0,0 @@
package org.kar.karusic.api;
import java.io.InputStream;
import java.util.List;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany;
import org.kar.archidata.tools.DataTools;
import org.kar.karusic.model.Album;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST;
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;
@Path("/album")
@Produces({ MediaType.APPLICATION_JSON })
public class AlbumResource {
@GET
@Path("{id}")
@RolesAllowed("USER")
public static Album getWithId(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(Album.class, id);
}
@GET
@RolesAllowed("USER")
public List<Album> get() throws Exception {
return DataAccess.gets(Album.class);
}
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Album post(final String jsonRequest) throws Exception {
return DataAccess.insertWithJson(Album.class, jsonRequest);
}
@PATCH
@Path("{id}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Album put(@PathParam("id") final Long id, final String jsonRequest) throws Exception {
DataAccess.updateWithJson(Album.class, id, jsonRequest);
return DataAccess.get(Album.class, id);
}
@DELETE
@Path("{id}")
@RolesAllowed("ADMIN")
public Response delete(@PathParam("id") final Long id) throws Exception {
DataAccess.delete(Album.class, id);
return Response.ok().build();
}
@POST
@Path("{id}/add_track/{trackId}")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
public Album addTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception {
AddOnManyToMany.removeLink(Album.class, id, "track", trackId);
return DataAccess.get(Album.class, id);
}
@GET
@Path("{id}/rm_track/{trackId}")
@RolesAllowed("ADMIN")
public Album removeTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception {
AddOnManyToMany.removeLink(Album.class, id, "track", trackId);
return DataAccess.get(Album.class, id);
}
@POST
@Path("{id}/add_cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream,
@FormDataParam("file") final FormDataContentDisposition fileMetaData) {
return DataTools.uploadCover(Album.class, id, fileName, fileInputStream, fileMetaData);
}
@GET
@Path("{id}/rm_cover/{coverId}")
@RolesAllowed("ADMIN")
public Response removeCover(@PathParam("id") final Long id, @PathParam("coverId") final Long coverId) throws Exception {
AddOnManyToMany.removeLink(Album.class, id, "cover", coverId);
return Response.ok(DataAccess.get(Album.class, id)).build();
}
}

View File

@ -1,82 +0,0 @@
package org.kar.karusic.api;
import java.io.InputStream;
import java.util.List;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany;
import org.kar.archidata.tools.DataTools;
import org.kar.karusic.model.Artist;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST;
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;
@Path("/artist")
@Produces({ MediaType.APPLICATION_JSON })
public class ArtistResource {
@GET
@Path("{id}")
@RolesAllowed("USER")
public static Artist getWithId(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(Artist.class, id);
}
@GET
@RolesAllowed("USER")
public List<Artist> get() throws Exception {
return DataAccess.gets(Artist.class);
}
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Artist put(final String jsonRequest) throws Exception {
return DataAccess.insertWithJson(Artist.class, jsonRequest);
}
@PATCH
@Path("{id}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Artist put(@PathParam("id") final Long id, final String jsonRequest) throws Exception {
DataAccess.updateWithJson(Artist.class, id, jsonRequest);
return DataAccess.get(Artist.class, id);
}
@DELETE
@Path("{id}")
@RolesAllowed("ADMIN")
public Response delete(@PathParam("id") final Long id) throws Exception {
DataAccess.delete(Artist.class, id);
return Response.ok().build();
}
@POST
@Path("{id}/add_cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream,
@FormDataParam("file") final FormDataContentDisposition fileMetaData) {
return DataTools.uploadCover(Artist.class, id, fileName, fileInputStream, fileMetaData);
}
@GET
@Path("{id}/rm_cover/{coverId}")
@RolesAllowed("ADMIN")
public Response removeCover(@PathParam("id") final Long id, @PathParam("coverId") final Long coverId) throws Exception {
AddOnManyToMany.removeLink(Artist.class, id, "cover", coverId);
return Response.ok(DataAccess.get(Artist.class, id)).build();
}
}

View File

@ -1,82 +0,0 @@
package org.kar.karusic.api;
import java.io.InputStream;
import java.util.List;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany;
import org.kar.archidata.tools.DataTools;
import org.kar.karusic.model.Gender;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST;
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;
@Path("/gender")
@Produces({ MediaType.APPLICATION_JSON })
public class GenderResource {
@GET
@Path("{id}")
@RolesAllowed("USER")
public static Gender getWithId(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(Gender.class, id);
}
@GET
@RolesAllowed("USER")
public List<Gender> get() throws Exception {
return DataAccess.gets(Gender.class);
}
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Gender put(final String jsonRequest) throws Exception {
return DataAccess.insertWithJson(Gender.class, jsonRequest);
}
@PATCH
@Path("{id}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Gender put(@PathParam("id") final Long id, final String jsonRequest) throws Exception {
DataAccess.updateWithJson(Gender.class, id, jsonRequest);
return DataAccess.get(Gender.class, id);
}
@DELETE
@Path("{id}")
@RolesAllowed("ADMIN")
public Response delete(@PathParam("id") final Long id) throws Exception {
DataAccess.delete(Gender.class, id);
return Response.ok().build();
}
@POST
@Path("{id}/add_cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream,
@FormDataParam("file") final FormDataContentDisposition fileMetaData) {
return DataTools.uploadCover(Gender.class, id, fileName, fileInputStream, fileMetaData);
}
@GET
@Path("{id}/rm_cover/{coverId}")
@RolesAllowed("ADMIN")
public Response removeCover(@PathParam("id") final Long id, @PathParam("coverId") final Long coverId) throws Exception {
AddOnManyToMany.removeLink(Gender.class, id, "cover", coverId);
return Response.ok(DataAccess.get(Gender.class, id)).build();
}
}

View File

@ -1,99 +0,0 @@
package org.kar.karusic.api;
import java.io.InputStream;
import java.util.List;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany;
import org.kar.archidata.tools.DataTools;
import org.kar.karusic.model.Playlist;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST;
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;
@Path("/playlist")
@Produces({ MediaType.APPLICATION_JSON })
public class PlaylistResource {
@GET
@Path("{id}")
@RolesAllowed("USER")
public static Playlist getWithId(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(Playlist.class, id);
}
@GET
@RolesAllowed("USER")
public List<Playlist> get() throws Exception {
return DataAccess.gets(Playlist.class);
}
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Playlist put(final String jsonRequest) throws Exception {
return DataAccess.insertWithJson(Playlist.class, jsonRequest);
}
@PATCH
@Path("{id}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Playlist put(@PathParam("id") final Long id, final String jsonRequest) throws Exception {
DataAccess.updateWithJson(Playlist.class, id, jsonRequest);
return DataAccess.get(Playlist.class, id);
}
@DELETE
@Path("{id}")
@RolesAllowed("ADMIN")
public Response delete(@PathParam("id") final Long id) throws Exception {
DataAccess.delete(Playlist.class, id);
return Response.ok().build();
}
@POST
@Path("{id}/add_track/{trackId}")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
public Playlist addTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception {
AddOnManyToMany.removeLink(Playlist.class, id, "track", trackId);
return DataAccess.get(Playlist.class, id);
}
@GET
@Path("{id}/rm_track/{trackId}")
@RolesAllowed("ADMIN")
public Playlist removeTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception {
AddOnManyToMany.removeLink(Playlist.class, id, "track", trackId);
return DataAccess.get(Playlist.class, id);
}
@POST
@Path("{id}/add_cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream,
@FormDataParam("file") final FormDataContentDisposition fileMetaData) {
return DataTools.uploadCover(Playlist.class, id, fileName, fileInputStream, fileMetaData);
}
@GET
@Path("{id}/rm_cover/{coverId}")
@RolesAllowed("ADMIN")
public Response removeCover(@PathParam("id") final Long id, @PathParam("coverId") final Long coverId) throws Exception {
AddOnManyToMany.removeLink(Playlist.class, id, "cover", coverId);
return Response.ok(DataAccess.get(Playlist.class, id)).build();
}
}

View File

@ -1,240 +0,0 @@
package org.kar.karusic.api;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.QueryCondition;
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany;
import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.model.Data;
import org.kar.archidata.tools.DataTools;
import org.kar.karusic.model.Album;
import org.kar.karusic.model.Artist;
import org.kar.karusic.model.Gender;
import org.kar.karusic.model.Track;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST;
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;
@Path("/track")
@Produces({ MediaType.APPLICATION_JSON })
public class TrackResource {
@GET
@Path("{id}")
@RolesAllowed("USER")
public static Track getWithId(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(Track.class, id);
}
@GET
@RolesAllowed("USER")
public List<Track> get() throws Exception {
return DataAccess.gets(Track.class);
}
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Track create(final String jsonRequest) throws Exception {
return DataAccess.insertWithJson(Track.class, jsonRequest);
}
@PATCH
@Path("{id}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Track put(@PathParam("id") final Long id, final String jsonRequest) throws Exception {
DataAccess.updateWithJson(Track.class, id, jsonRequest);
return DataAccess.get(Track.class, id);
}
@DELETE
@Path("{id}")
@RolesAllowed("ADMIN")
public Response delete(@PathParam("id") final Long id) throws Exception {
DataAccess.delete(Track.class, id);
return Response.ok().build();
}
@POST
@Path("{id}/add_artist/{artistId}")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
public Track addTrack(@PathParam("id") final Long id, @PathParam("artistId") final Long artistId) throws Exception {
AddOnManyToMany.removeLink(Track.class, id, "artist", artistId);
return DataAccess.get(Track.class, id);
}
@GET
@Path("{id}/rm_artist/{trackId}")
@RolesAllowed("ADMIN")
public Track removeTrack(@PathParam("id") final Long id, @PathParam("artistId") final Long artistId) throws Exception {
AddOnManyToMany.removeLink(Track.class, id, "artist", artistId);
return DataAccess.get(Track.class, id);
}
@POST
@Path("{id}/add_cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream,
@FormDataParam("file") final FormDataContentDisposition fileMetaData) {
return DataTools.uploadCover(Track.class, id, fileName, fileInputStream, fileMetaData);
}
@GET
@Path("{id}/rm_cover/{coverId}")
@RolesAllowed("ADMIN")
public Response removeCover(@PathParam("id") final Long id, @PathParam("coverId") final Long coverId) throws Exception {
AddOnManyToMany.removeLink(Track.class, id, "cover", coverId);
return Response.ok(DataAccess.get(Track.class, id)).build();
}
@POST
@Path("/upload/")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
public Response uploadFile(@FormDataParam("fileName") String fileName, @FormDataParam("gender") String gender, @FormDataParam("artist") String artist,
//@FormDataParam("seriesId") String seriesId, Not used ...
@FormDataParam("album") String album, @FormDataParam("trackId") String trackId, @FormDataParam("title") String title, @FormDataParam("file") final InputStream fileInputStream,
@FormDataParam("file") final FormDataContentDisposition fileMetaData) {
try {
// correct input string stream :
fileName = DataTools.multipartCorrection(fileName);
gender = DataTools.multipartCorrection(gender);
artist = DataTools.multipartCorrection(artist);
album = DataTools.multipartCorrection(album);
trackId = DataTools.multipartCorrection(trackId);
title = DataTools.multipartCorrection(title);
//public NodeSmall uploadFile(final FormDataMultiPart form) {
System.out.println("Upload media file: " + fileMetaData);
System.out.println(" - fileName: " + fileName);
System.out.println(" - gender: " + gender);
System.out.println(" - artist: " + artist);
System.out.println(" - album: " + album);
System.out.println(" - trackId: " + trackId);
System.out.println(" - title: " + title);
System.out.println(" - fileInputStream: " + fileInputStream);
System.out.println(" - fileMetaData: " + fileMetaData);
System.out.flush();
/*
if (typeId == null) {
return Response.status(406).
entity("Missong Input 'type'").
type("text/plain").
build();
}
*/
final long tmpUID = DataTools.getTmpDataId();
final String sha512 = DataTools.saveTemporaryFile(fileInputStream, tmpUID);
Data data = DataTools.getWithSha512(sha512);
if (data == null) {
System.out.println("Need to add the data in the BDD ... ");
System.out.flush();
try {
data = DataTools.createNewData(tmpUID, fileName, sha512);
} catch (final IOException ex) {
DataTools.removeTemporaryFile(tmpUID);
ex.printStackTrace();
return Response.notModified("can not create input media").build();
} catch (final SQLException ex) {
ex.printStackTrace();
DataTools.removeTemporaryFile(tmpUID);
return Response.notModified("Error in SQL insertion ...").build();
}
} else if (data.deleted) {
System.out.println("Data already exist but deleted");
System.out.flush();
DataTools.undelete(data.id);
data.deleted = false;
} else {
System.out.println("Data already exist ... all good");
System.out.flush();
}
// Fist step: retrieve all the Id of each parents:...
System.out.println("Find typeNode");
Gender genderElem = null;
if (gender != null) {
genderElem = DataAccess.getWhere(Gender.class, new Condition(new QueryCondition("name", "=", gender)));
if (genderElem == null) {
genderElem = new Gender();
genderElem.name = gender;
genderElem = DataAccess.insert(genderElem);
}
}
// NodeSmall typeNode = TypeResource.getWithId(Long.parseLong(typeId));
// if (typeNode == null) {
// DataTools.removeTemporaryFile(tmpUID);
// return Response.notModified("TypeId does not exist ...").build();
// }
System.out.println(" ==> " + genderElem);
Artist artistElem = null;
if (artist != null) {
artistElem = DataAccess.getWhere(Artist.class, new Condition(new QueryCondition("name", "=", artist)));
if (artistElem == null) {
artistElem = new Artist();
artistElem.name = artist;
artistElem = DataAccess.insert(artistElem);
}
}
System.out.println(" ==> " + artistElem);
Album albumElem = null;
if (album != null) {
albumElem = DataAccess.getWhere(Album.class, new Condition(new QueryCondition("name", "=", album)));
if (albumElem == null) {
albumElem = new Album();
albumElem.name = album;
albumElem = DataAccess.insert(albumElem);
}
}
System.out.println(" ==> " + album);
System.out.println("add media");
Track trackElem = new Track();
trackElem.name = title;
trackElem.track = trackId != null ? Long.parseLong(trackId) : null;
trackElem.albumId = albumElem != null ? albumElem.id : null;
trackElem.genderId = genderElem != null ? genderElem.id : null;
trackElem.dataId = data.id;
// Now list of artis has an internal management:
if (artistElem != null) {
trackElem.artists = new ArrayList<>();
trackElem.artists.add(artistElem.id);
}
trackElem = DataAccess.insert(trackElem);
/*
Old mode of artist insertion (removed due to the slowlest request of getting value
if (artistElem != null) {
DataAccess.addLink(Track.class, trackElem.id, "artist", artistElem.id);
}
*/
return Response.ok(trackElem).build();
} catch (final Exception ex) {
System.out.println("Catch an unexpected error ... " + ex.getMessage());
ex.printStackTrace();
return Response.status(417).entity("Back-end error : " + ex.getMessage()).type("text/plain").build();
}
}
}

View File

@ -1,60 +0,0 @@
package org.kar.karusic.internal;
//import io.scenarium.logger.LogLevel;
//import io.scenarium.logger.Logger;
public class Log {
// private static final String LIB_NAME = "logger";
// private static final String LIB_NAME_DRAW = Logger.getDrawableName(LIB_NAME);
// private static final boolean PRINT_CRITICAL = Logger.getNeedPrint(LIB_NAME, LogLevel.CRITICAL);
// private static final boolean PRINT_ERROR = Logger.getNeedPrint(LIB_NAME, LogLevel.ERROR);
// private static final boolean PRINT_WARNING = Logger.getNeedPrint(LIB_NAME, LogLevel.WARNING);
// private static final boolean PRINT_INFO = Logger.getNeedPrint(LIB_NAME, LogLevel.INFO);
// private static final boolean PRINT_DEBUG = Logger.getNeedPrint(LIB_NAME, LogLevel.DEBUG);
// private static final boolean PRINT_VERBOSE = Logger.getNeedPrint(LIB_NAME, LogLevel.VERBOSE);
// private static final boolean PRINT_TODO = Logger.getNeedPrint(LIB_NAME, LogLevel.TODO);
// private static final boolean PRINT_PRINT = Logger.getNeedPrint(LIB_NAME, LogLevel.PRINT);
//
// private Log() {}
//
// public static void print(String data) {
// if (PRINT_PRINT)
// Logger.print(LIB_NAME_DRAW, data);
// }
//
// public static void todo(String data) {
// if (PRINT_TODO)
// Logger.todo(LIB_NAME_DRAW, data);
// }
//
// public static void critical(String data) {
// if (PRINT_CRITICAL)
// Logger.critical(LIB_NAME_DRAW, data);
// }
//
// public static void error(String data) {
// if (PRINT_ERROR)
// Logger.error(LIB_NAME_DRAW, data);
// }
//
// public static void warning(String data) {
// if (PRINT_WARNING)
// Logger.warning(LIB_NAME_DRAW, data);
// }
//
// public static void info(String data) {
// if (PRINT_INFO)
// Logger.info(LIB_NAME_DRAW, data);
// }
//
// public static void debug(String data) {
// if (PRINT_DEBUG)
// Logger.debug(LIB_NAME_DRAW, data);
// }
//
// public static void verbose(String data) {
// if (PRINT_VERBOSE)
// Logger.verbose(LIB_NAME_DRAW, data);
// }
}

View File

@ -1,88 +0,0 @@
package org.kar.karusic.migration;
import org.kar.archidata.migration.MigrationSqlStep;
import org.kar.archidata.model.Data;
import org.kar.archidata.model.User;
import org.kar.karusic.model.Album;
import org.kar.karusic.model.Artist;
import org.kar.karusic.model.Gender;
import org.kar.karusic.model.Playlist;
import org.kar.karusic.model.Track;
public class Initialization extends MigrationSqlStep {
public static final int KARSO_INITIALISATION_ID = 1;
@Override
public String getName() {
return "Initialization";
}
public Initialization() {
}
@Override
public void generateStep() throws Exception {
addClass(Album.class);
addClass(Artist.class);
addClass(Data.class);
addClass(Gender.class);
addClass(Playlist.class);
addClass(Track.class);
addClass(User.class);
addAction("""
INSERT INTO `gender` (`id`, `name`, `description`) VALUES
(1, 'Variété française', NULL),
(2, 'Pop', NULL),
(3, 'inconnue', NULL),
(4, 'Disco', NULL),
(5, 'Enfants', NULL),
(6, 'Portugaise', NULL),
(7, 'Apprentissage', NULL),
(8, 'Blues', NULL),
(9, 'Jazz', NULL),
(10, 'Chanson Noël', NULL),
(11, 'DubStep', NULL),
(12, 'Rap français', NULL),
(13, 'Classique', NULL),
(14, 'Rock', NULL),
(15, 'Electro', NULL),
(16, 'Celtique', NULL),
(17, 'Country', NULL),
(18, 'Variété Québéquoise', NULL),
(19, 'Médiéval', NULL),
(20, 'Variété Italienne', NULL),
(21, 'Comédie Musicale', NULL),
(22, 'Vianney', NULL),
(23, 'Bande Original', NULL),
(24, 'Bande Originale', NULL),
(25, 'Variété Belge', NULL),
(26, 'Gospel', NULL);
""");
// set start increment element to permit to add after default elements
addAction("""
ALTER TABLE `album` AUTO_INCREMENT = 1000;
""", "mysql");
addAction("""
ALTER TABLE `artist` AUTO_INCREMENT = 1000;
""", "mysql");
addAction("""
ALTER TABLE `data` AUTO_INCREMENT = 1000;
""", "mysql");
addAction("""
ALTER TABLE `gender` AUTO_INCREMENT = 1000;
""", "mysql");
addAction("""
ALTER TABLE `playlist` AUTO_INCREMENT = 1000;
""", "mysql");
addAction("""
ALTER TABLE `track` AUTO_INCREMENT = 1000;
""", "mysql");
addAction("""
ALTER TABLE `user` AUTO_INCREMENT = 1000;
""", "mysql");
}
}

View File

@ -1,169 +0,0 @@
package org.kar.karusic.migration;
import org.kar.archidata.migration.MigrationSqlStep;
public class Migration20231126 extends MigrationSqlStep {
public static final int KARSO_INITIALISATION_ID = 1;
@Override
public String getName() {
return "migration-2023-11-26: reorder the migration for the new API of archidata";
}
public Migration20231126() {
}
@Override
public void generateStep() throws Exception {
// update migration update (last one)
addAction("""
ALTER TABLE `KAR_migration`
CHANGE `id` `id` bigint NOT NULL COMMENT 'Primary key of the base' AUTO_INCREMENT FIRST,
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Create time of the object' AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'When update the object' AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'When delete, they are not removed, they are just set in a deleted state' AFTER `updatedAt`,
ADD `version` int NOT NULL DEFAULT '2' AFTER `deleted`,
CHANGE `name` `name` varchar(256) COLLATE 'utf8mb4_0900_ai_ci' NULL COMMENT 'Name of the migration' AFTER `version`,
CHANGE `terminated` `terminated` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'if the migration is well terminated or not' AFTER `name`,
CHANGE `stepId` `stepId` int NULL COMMENT 'index in the migration progression' AFTER `terminated`,
CHANGE `count` `count` int NULL COMMENT 'number of element in the migration' AFTER `stepId`,
CHANGE `log` `log` text COLLATE 'utf8mb3_general_ci' NULL COMMENT 'Log generate by the migration' AFTER `count`;
""");
addAction("""
ALTER TABLE `album`
CHANGE `id` `id` bigint NOT NULL COMMENT 'Primary key of the base' AUTO_INCREMENT FIRST,
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Create time of the object' AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'When update the object' AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'When delete, they are not removed, they are just set in a deleted state' AFTER `updatedAt`,
CHANGE `name` `name` varchar(256) COLLATE 'utf8mb4_0900_ai_ci' NULL AFTER `deleted`,
CHANGE `description` `description` text COLLATE 'utf8mb3_general_ci' NULL AFTER `name`,
CHANGE `publication` `publication` date NULL AFTER `description`;
""");
addAction("""
ALTER TABLE `album_link_cover`
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' AFTER `updatedAt`,
CHANGE `album_id` `object1id` bigint NOT NULL AFTER `deleted`,
CHANGE `cover_id` `object2id` bigint NOT NULL AFTER `object1id`;
""");
addAction("""
ALTER TABLE `artist`
CHANGE `id` `id` bigint NOT NULL COMMENT 'Primary key of the base' AUTO_INCREMENT FIRST,
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Create time of the object' AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'When update the object' AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'When delete, they are not removed, they are just set in a deleted state' AFTER `updatedAt`,
CHANGE `firstName` `firstName` varchar(256) COLLATE 'utf8mb4_0900_ai_ci' NULL AFTER `description`,
CHANGE `surname` `surname` varchar(256) COLLATE 'utf8mb4_0900_ai_ci' NULL AFTER `firstName`,
CHANGE `birth` `birth` date NULL AFTER `surname`,
CHANGE `death` `death` date NULL AFTER `birth`;
""");
addAction("""
ALTER TABLE `artist_link_cover`
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' AFTER `updatedAt`,
CHANGE `artist_id` `object1id` bigint NOT NULL AFTER `deleted`,
CHANGE `cover_id` `object2id` bigint NOT NULL AFTER `object1id`;
""");
addAction("""
ALTER TABLE `data`
CHANGE `id` `id` bigint NOT NULL COMMENT 'Primary key of the base' AUTO_INCREMENT FIRST,
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Create time of the object' AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'When update the object' AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'When delete, they are not removed, they are just set in a deleted state' AFTER `updatedAt`,
CHANGE `sha512` `sha512` varchar(128) COLLATE 'utf8mb4_0900_ai_ci' NOT NULL COMMENT 'Sha512 of the data' AFTER `deleted`,
CHANGE `mimeType` `mimeType` varchar(128) COLLATE 'utf8mb4_0900_ai_ci' NOT NULL COMMENT 'Mime -type of the media' AFTER `sha512`,
CHANGE `size` `size` bigint NOT NULL COMMENT 'Size in Byte of the data' AFTER `mimeType`;
""");
addAction("""
ALTER TABLE `gender`
CHANGE `id` `id` bigint NOT NULL COMMENT 'Primary key of the base' AUTO_INCREMENT FIRST,
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Create time of the object' AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'When update the object' AFTER `createdAt`,
CHANGE `name` `name` varchar(256) COLLATE 'utf8mb4_0900_ai_ci' NULL AFTER `deleted`,
CHANGE `description` `description` text COLLATE 'utf8mb3_general_ci' NULL AFTER `name`;
""");
addAction("""
ALTER TABLE `gender_link_cover`
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' AFTER `updatedAt`,
CHANGE `gender_id` `object1id` bigint NOT NULL AFTER `deleted`,
CHANGE `cover_id` `object2id` bigint NOT NULL AFTER `object1id`;
""");
addAction("""
ALTER TABLE `playlist`
CHANGE `id` `id` bigint NOT NULL COMMENT 'Primary key of the base' AUTO_INCREMENT FIRST,
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Create time of the object' AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'When update the object' AFTER `createdAt`,
CHANGE `name` `name` varchar(256) COLLATE 'utf8mb4_0900_ai_ci' NULL AFTER `deleted`,
CHANGE `description` `description` text COLLATE 'utf8mb3_general_ci' NULL AFTER `name`;
""");
addAction("""
ALTER TABLE `playlist_link_cover`
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' AFTER `updatedAt`,
CHANGE `playlist_id` `object1id` bigint NOT NULL AFTER `deleted`,
CHANGE `cover_id` `object2id` bigint NOT NULL AFTER `object1id`;
""");
addAction("""
ALTER TABLE `playlist_link_track`
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' AFTER `updatedAt`,
CHANGE `playlist_id` `object1id` bigint NOT NULL AFTER `deleted`,
CHANGE `track_id` `object2id` bigint NOT NULL AFTER `object1id`;
""");
addAction("""
ALTER TABLE `track`
CHANGE `id` `id` bigint NOT NULL COMMENT 'Primary key of the base' AUTO_INCREMENT FIRST,
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Create time of the object' AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'When update the object' AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'When delete, they are not removed, they are just set in a deleted state' AFTER `updatedAt`,
CHANGE `name` `name` varchar(256) COLLATE 'utf8mb4_0900_ai_ci' NULL AFTER `deleted`,
CHANGE `description` `description` text COLLATE 'utf8mb3_general_ci' NULL AFTER `name`,
CHANGE `genderId` `genderId` bigint NULL AFTER `description`,
CHANGE `albumId` `albumId` bigint NULL AFTER `genderId`,
CHANGE `track` `track` bigint NULL AFTER `albumId`,
CHANGE `dataId` `dataId` bigint NULL AFTER `track`,
CHANGE `artists` `artists` text COLLATE 'utf8mb4_0900_ai_ci' NULL AFTER `dataId`;
""");
addAction("""
ALTER TABLE `track_link_cover`
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' AFTER `updatedAt`,
CHANGE `track_id` `object1id` bigint NOT NULL AFTER `deleted`,
CHANGE `cover_id` `object2id` bigint NOT NULL AFTER `object1id`;
""");
addAction("""
ALTER TABLE `user`
CHANGE `id` `id` bigint NOT NULL COMMENT 'Primary key of the base' AUTO_INCREMENT FIRST,
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Create time of the object' AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'When update the object' AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'When delete, they are not removed, they are just set in a deleted state' AFTER `updatedAt`,
CHANGE `login` `login` varchar(128) COLLATE 'utf8mb4_0900_ai_ci' NULL AFTER `deleted`,
CHANGE `lastConnection` `lastConnection` timestamp(3) NULL AFTER `login`,
CHANGE `admin` `admin` tinyint(1) NOT NULL DEFAULT '0' AFTER `lastConnection`,
CHANGE `blocked` `blocked` tinyint(1) NOT NULL DEFAULT '0' AFTER `admin`,
CHANGE `removed` `removed` tinyint(1) NOT NULL DEFAULT '0' AFTER `blocked`;
""");
addAction("""
CREATE TABLE `user_link_cover` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'Primary key of the base' ,
`createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Create time of the object' ,
`updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT 'When update the object' ,
`deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'When delete, they are not removed, they are just set in a deleted state' ,
`object1Id` bigint NOT NULL COMMENT 'Object reference 1' ,
`object2Id` bigint NOT NULL COMMENT 'Object reference 2' ,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
""");
}
}

View File

@ -1,16 +0,0 @@
package org.kar.karusic.model;
import java.time.LocalDate;
import org.kar.archidata.annotation.DataIfNotExists;
import com.fasterxml.jackson.annotation.JsonInclude;
import jakarta.persistence.Table;
@Table(name = "album")
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Album extends NodeSmall {
public LocalDate publication = null;
}

View File

@ -1,28 +0,0 @@
package org.kar.karusic.model;
import java.time.LocalDate;
import org.kar.archidata.annotation.DataIfNotExists;
import com.fasterxml.jackson.annotation.JsonInclude;
import jakarta.persistence.Column;
import jakarta.persistence.Table;
@Table(name = "artist")
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Artist extends NodeSmall {
@Column(length = 256)
public String firstName = null;
@Column(length = 256)
public String surname = null;
public LocalDate birth = null;
public LocalDate death = null;
@Override
public String toString() {
return "Artist [id=" + this.id + ", name=" + this.name + ", description=" + this.description + ", covers=" + this.covers + ", firstName=" + this.firstName + ", surname=" + this.surname
+ ", birth=" + this.birth + ", death=" + this.death + "]";
}
}

View File

@ -1,55 +0,0 @@
package org.kar.karusic.model;
/*
CREATE TABLE `data` (
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
`deleted` BOOLEAN NOT NULL DEFAULT false,
`create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created',
`modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update',
`sha512` varchar(129) COLLATE 'utf8_general_ci' NOT NULL,
`mime_type` varchar(128) COLLATE 'utf8_general_ci' NOT NULL,
`size` bigint,
`original_name` TEXT
) AUTO_INCREMENT=64;
*/
import java.sql.ResultSet;
import java.sql.SQLException;
public class DataSmall {
public Long id;
public String sha512;
public String mimeType;
public Long size;
public DataSmall() {
}
public DataSmall(ResultSet rs) {
int iii = 1;
try {
this.id = rs.getLong(iii++);
this.sha512 = rs.getString(iii++);
this.mimeType = rs.getString(iii++);
this.size = rs.getLong(iii++);
} catch (SQLException ex) {
ex.printStackTrace();
}
}
public String getTableSql() {
return """
DROP TABLE IF EXISTS `data`;
CREATE TABLE `data` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'table ID',
`deleted` tinyint(1) NOT NULL DEFAULT '0',
`create_date` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Time the element has been created',
`modify_date` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Time the element has been update',
`sha512` varchar(129) CHARACTER SET utf8mb3 COLLATE utf8_general_ci NOT NULL,
`mime_type` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8_general_ci NOT NULL,
`size` bigint DEFAULT NULL,
`original_name` text,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
""";
}
}

View File

@ -1,26 +0,0 @@
package org.kar.karusic.model;
/*
CREATE TABLE `node` (
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
`deleted` BOOLEAN NOT NULL DEFAULT false,
`create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created',
`modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update',
`type` enum("TYPE", "UNIVERS", "SERIE", "SAISON", "MEDIA") NOT NULL DEFAULT 'TYPE',
`name` TEXT COLLATE 'utf8_general_ci' NOT NULL,
`description` TEXT COLLATE 'utf8_general_ci',
`parent_id` bigint
) AUTO_INCREMENT=10;
*/
import org.kar.archidata.annotation.DataIfNotExists;
import com.fasterxml.jackson.annotation.JsonInclude;
import jakarta.persistence.Table;
@Table(name = "gender")
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Gender extends NodeSmall {
}

View File

@ -1,104 +0,0 @@
package org.kar.karusic.model;
/*
CREATE TABLE `node` (
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
`deleted` BOOLEAN NOT NULL DEFAULT false,
`create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created',
`modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update',
`type` enum("TYPE", "UNIVERSE", "SERIES", "SEASON") NOT NULL DEFAULT 'TYPE',
`name` TEXT COLLATE 'utf8_general_ci' NOT NULL,
`description` TEXT COLLATE 'utf8_general_ci',
`parent_id` bigint
) AUTO_INCREMENT=10;
*/
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MediaSmall {
public class MediaStreamProperty {
public Long id;
public Long timeSecond;
public Long width;
public Long height;
public Map<String, Long> videos = new HashMap<>();
public Map<String, Long> audios = new HashMap<>();
public Map<String, Long> subtitles = new HashMap<>();
}
public Long id;
public String name;
public String description;
public Long dataId;
public Long typeId;
public Long universeId;
public Long seriesId;
public Long seasonId;
public Integer episode;
public Integer date;
public Integer time;
public String ageLimit;
public List<Long> covers = null;
public MediaStreamProperty media;
public MediaSmall(ResultSet rs) {
int iii = 1;
try {
this.id = rs.getLong(iii++);
this.name = rs.getString(iii++);
this.description = rs.getString(iii++);
this.dataId = rs.getLong(iii++);
if (rs.wasNull()) {
this.dataId = null;
}
this.typeId = rs.getLong(iii++);
if (rs.wasNull()) {
this.typeId = null;
}
this.universeId = rs.getLong(iii++);
if (rs.wasNull()) {
this.universeId = null;
}
this.seriesId = rs.getLong(iii++);
if (rs.wasNull()) {
this.seriesId = null;
}
this.seasonId = rs.getLong(iii++);
if (rs.wasNull()) {
this.seasonId = null;
}
this.episode = rs.getInt(iii++);
if (rs.wasNull()) {
this.episode = null;
}
this.date = rs.getInt(iii++);
if (rs.wasNull()) {
this.date = null;
}
this.time = rs.getInt(iii++);
if (rs.wasNull()) {
this.time = null;
}
this.ageLimit = rs.getString(iii++);
String coversString = rs.getString(iii++);
if (!rs.wasNull()) {
covers = new ArrayList<>();
String[] elements = coversString.split("-");
for (String elem : elements) {
Long tmp = Long.parseLong(elem);
covers.add(tmp);
}
}
} catch (SQLException ex) {
ex.printStackTrace();
}
}
}

View File

@ -1,34 +0,0 @@
package org.kar.karusic.model;
/*
CREATE TABLE `node` (
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
`deleted` BOOLEAN NOT NULL DEFAULT false,
`create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created',
`modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update',
`type` enum("TYPE", "UNIVERS", "SERIE", "SAISON", "MEDIA") NOT NULL DEFAULT 'TYPE',
`name` TEXT COLLATE 'utf8_general_ci' NOT NULL,
`description` TEXT COLLATE 'utf8_general_ci',
`parent_id` bigint
) AUTO_INCREMENT=10;
*/
import java.util.List;
import org.kar.archidata.model.Data;
import org.kar.archidata.model.GenericDataSoftDelete;
import com.fasterxml.jackson.annotation.JsonInclude;
import jakarta.persistence.Column;
import jakarta.persistence.FetchType;
import jakarta.persistence.ManyToMany;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class NodeSmall extends GenericDataSoftDelete {
@Column(length = 256)
public String name = null;
@Column(length = 0)
public String description = null;
@ManyToMany(fetch = FetchType.LAZY, targetEntity = Data.class)
public List<Long> covers = null;
}

View File

@ -1,31 +0,0 @@
package org.kar.karusic.model;
/*
CREATE TABLE `node` (
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
`deleted` BOOLEAN NOT NULL DEFAULT false,
`create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created',
`modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update',
`type` enum("TYPE", "UNIVERS", "SERIE", "SAISON", "MEDIA") NOT NULL DEFAULT 'TYPE',
`name` TEXT COLLATE 'utf8_general_ci' NOT NULL,
`description` TEXT COLLATE 'utf8_general_ci',
`parent_id` bigint
) AUTO_INCREMENT=10;
*/
import java.util.List;
import org.kar.archidata.annotation.DataIfNotExists;
import com.fasterxml.jackson.annotation.JsonInclude;
import jakarta.persistence.FetchType;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.Table;
@Table(name = "playlist")
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Playlist extends NodeSmall {
@ManyToMany(fetch = FetchType.LAZY, targetEntity = Track.class)
public List<Long> tracks = null;
}

View File

@ -1,10 +0,0 @@
package org.kar.karusic.model;
public enum State {
// User has remove his account
REMOVED,
// User has been blocked his account
BLOCKED,
// generic user
USER
}

View File

@ -1,43 +0,0 @@
package org.kar.karusic.model;
/*
CREATE TABLE `node` (
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
`deleted` BOOLEAN NOT NULL DEFAULT false,
`create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created',
`modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update',
`type` enum("TYPE", "UNIVERS", "SERIE", "SAISON", "MEDIA") NOT NULL DEFAULT 'TYPE',
`name` TEXT COLLATE 'utf8_general_ci' NOT NULL,
`description` TEXT COLLATE 'utf8_general_ci',
`parent_id` bigint
) AUTO_INCREMENT=10;
*/
import java.util.List;
import org.kar.archidata.annotation.DataIfNotExists;
import org.kar.archidata.annotation.addOn.SQLTableExternalForeinKeyAsList;
import com.fasterxml.jackson.annotation.JsonInclude;
import jakarta.persistence.Column;
import jakarta.persistence.Table;
@Table(name = "track")
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Track extends NodeSmall {
public Long genderId = null;
public Long albumId = null;
public Long track = null;
public Long dataId = null;
//@ManyToMany(fetch = FetchType.LAZY, targetEntity = Artist.class)
@SQLTableExternalForeinKeyAsList
@Column(length = 0)
public List<Long> artists = null;
@Override
public String toString() {
return "Track [id=" + this.id + ", deleted=" + this.deleted + ", createdAt=" + this.createdAt + ", updatedAt=" + this.updatedAt + ", name=" + this.name + ", description=" + this.description
+ ", covers=" + this.covers + ", genderId=" + this.genderId + ", albumId=" + this.albumId + ", track=" + this.track + ", dataId=" + this.dataId + ", artists=" + this.artists + "]";
}
}

View File

@ -1,15 +0,0 @@
package org.kar.karusic.util;
public class ConfigVariable {
public static final String BASE_NAME = "ORG_KARUSIC_";
public static String getFrontFolder() {
String out = System.getenv(BASE_NAME + "FRONT_FOLDER");
if (out == null) {
return "/application/front";
}
return out;
}
}

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- environment detection (defaut: dev) -->
<property name="LOG_LEVEL_ENV" value="${LOG_LEVEL:-dev}" />
<!-- Appender for development -->
<if condition="property(&quot;LOG_LEVEL_ENV&quot;).equals(&quot;dev&quot;)">
<then>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%green(%d{HH:mm:ss.SSS}) %highlight(%-5level) %-30((%file:%line\)): %msg%n</pattern>
</encoder>
</appender>
<logger name="org.atriasoft.karusic" level="TRACE" />
<logger name="org.atriasoft.archidata" level="DEBUG" />
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</then>
</if>
<!-- Appender for production -->
<if condition="property(&quot;LOG_LEVEL_ENV&quot;).matches(&quot;^prod.*&quot;)">
<then>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%thread] %level %logger - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</then>
</if>
<if condition="property(&quot;LOG_LEVEL_ENV&quot;).equals(&quot;prod-debug&quot;)">
<then>
<logger name="org.atriasoft.karusic" level="DEBUG" />
</then>
</if>
<if condition="property(&quot;LOG_LEVEL_ENV&quot;).equals(&quot;prod-trace&quot;)">
<then>
<logger name="org.atriasoft.karusic" level="TRACE" />
<logger name="org.atriasoft.archidata" level="DEBUG" />
</then>
</if>
<if condition="property(&quot;LOG_LEVEL_ENV&quot;).equals(&quot;prod-trace-full&quot;)">
<then>
<logger name="org.atriasoft.karusic" level="TRACE" />
<logger name="org.atriasoft.archidata" level="TRACE" />
</then>
</if>
</configuration>

View File

@ -1,35 +0,0 @@
# SLF4J's SimpleLogger configuration file
# Simple implementation of Logger that sends all enabled log messages, for all defined loggers, to System.err.
# Default logging detail level for all instances of SimpleLogger.
# Must be one of ("trace", "debug", "info", "warn", or "error").
# If not specified, defaults to "info".
org.slf4j.simpleLogger.defaultLogLevel=trace
# Logging detail level for a SimpleLogger instance named "xxxxx".
# Must be one of ("trace", "debug", "info", "warn", or "error").
# If not specified, the default logging detail level is used.
#org.slf4j.simpleLogger.log.xxxxx=
# Set to true if you want the current date and time to be included in output messages.
# Default is false, and will output the number of milliseconds elapsed since startup.
#org.slf4j.simpleLogger.showDateTime=false
# The date and time format to be used in the output messages.
# The pattern describing the date and time format is the same that is used in java.text.SimpleDateFormat.
# If the format is not specified or is invalid, the default format is used.
# The default format is yyyy-MM-dd HH:mm:ss:SSS Z.
#org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss:SSS Z
# Set to true if you want to output the current thread name.
# Defaults to true.
org.slf4j.simpleLogger.showThreadName=true
# Set to true if you want the Logger instance name to be included in output messages.
# Defaults to true.
#org.slf4j.simpleLogger.showLogName=true
# Set to true if you want the last component of the name to be included in output messages.
# Defaults to false.
#org.slf4j.simpleLogger.showShortLogName=false

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,11 @@
package test.atriasoft.karusic;
import java.util.Map;
import org.atriasoft.archidata.filter.PartRight;
import org.atriasoft.archidata.tools.JWTWrapper;
public class Common {
static String USER_TOKEN = JWTWrapper.createJwtTestToken(16512, "test_user_login", "KarAuth", "karusic", Map.of("karusic", Map.of("USER", PartRight.READ)));
static String ADMIN_TOKEN = JWTWrapper.createJwtTestToken(16512, "test_admin_login", "KarAuth", "karusic", Map.of("karusic", Map.of("USER", PartRight.READ_WRITE, "ADMIN", PartRight.READ_WRITE)));
}

View File

@ -0,0 +1,115 @@
package test.atriasoft.karusic;
import java.io.IOException;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.db.DbConfig;
import org.atriasoft.archidata.db.DbIoFactory;
import org.atriasoft.archidata.exception.DataAccessException;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.InternalServerErrorException;
public class ConfigureDb {
final static private Logger LOGGER = LoggerFactory.getLogger(ConfigureDb.class);
final static private String modeTestForced = null;// "MONGO";
public static DBAccess da = null;
public static void configure() throws IOException, InternalServerErrorException, DataAccessException {
String modeTest = System.getenv("TEST_E2E_MODE");
if (modeTest == null || modeTest.isEmpty() || "false".equalsIgnoreCase(modeTest)) {
modeTest = "SQLITE-MEMORY";
} else if ("true".equalsIgnoreCase(modeTest)) {
modeTest = "MY-SQL";
}
// override the local test:
if (modeTestForced != null) {
modeTest = modeTestForced;
}
// for local test:
ConfigBaseVariable.apiAdress = "http://127.0.0.1:12342/test/api/";
// Enable the test mode permit to access to the test token (never use it in production).
ConfigBaseVariable.testMode = "true";
if ("SQLITE-MEMORY".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "sqlite";
ConfigBaseVariable.bdDatabase = null;
ConfigBaseVariable.dbHost = "memory";
// for test we need to connect all time the DB
ConfigBaseVariable.dbKeepConnected = "true";
} else if ("SQLITE".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "sqlite";
ConfigBaseVariable.bdDatabase = null;
ConfigBaseVariable.dbKeepConnected = "true";
} else if ("MY-SQL".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "mysql";
ConfigBaseVariable.bdDatabase = "test.atriasoftusic_db";
ConfigBaseVariable.dbPort = "3906";
ConfigBaseVariable.dbUser = "root";
} else if ("MONGO".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "mongo";
ConfigBaseVariable.bdDatabase = "test.atriasoftusic_db";
} else {
// User local modification ...
ConfigBaseVariable.bdDatabase = "test.atriasoftusic_db";
ConfigBaseVariable.dbPort = "3906";
ConfigBaseVariable.dbUser = "root";
}
removeDB();
// Connect the dataBase...
da = DBAccess.createInterface();
}
public static void removeDB() {
String modeTest = System.getenv("TEST_E2E_MODE");
if (modeTest == null || modeTest.isEmpty() || "false".equalsIgnoreCase(modeTest)) {
modeTest = "SQLITE-MEMORY";
} else if ("true".equalsIgnoreCase(modeTest)) {
modeTest = "MY-SQL";
}
// override the local test:
if (modeTestForced != null) {
modeTest = modeTestForced;
}
DbConfig config = null;
try {
config = new DbConfig();
} catch (final DataAccessException e) {
e.printStackTrace();
LOGGER.error("Fail to clean the DB");
return;
}
config.setDbName(null);
LOGGER.info("Remove the DB and create a new one '{}'", config.getDbName());
try (final DBAccess daRoot = DBAccess.createInterface(config)) {
if ("SQLITE-MEMORY".equalsIgnoreCase(modeTest)) {
// nothing to do ...
} else if ("SQLITE".equalsIgnoreCase(modeTest)) {
daRoot.deleteDB(ConfigBaseVariable.bdDatabase);
} else if ("MY-SQL".equalsIgnoreCase(modeTest)) {
daRoot.deleteDB(ConfigBaseVariable.bdDatabase);
} else if ("MONGO".equalsIgnoreCase(modeTest)) {
daRoot.deleteDB(ConfigBaseVariable.bdDatabase);
}
daRoot.createDB(ConfigBaseVariable.bdDatabase);
} catch (final InternalServerErrorException e) {
e.printStackTrace();
LOGGER.error("Fail to clean the DB");
return;
} catch (final IOException e) {
e.printStackTrace();
LOGGER.error("Fail to clean the DB");
return;
}
}
public static void clear() throws IOException {
LOGGER.info("Remove the test db");
removeDB();
// The connection is by default open ==> close it at the end of test:
da.close();
DbIoFactory.closeAllForceMode();
ConfigBaseVariable.clearAllValue();
}
}

View File

@ -0,0 +1,15 @@
package test.atriasoft.karusic;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Objects;
public class ResourceUtils {
public static File getResourceFile(final String resourcePath) throws IOException {
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
final URL resource = Objects.requireNonNull(classLoader.getResource(resourcePath), "Fichier non trouvé : " + resourcePath);
return new File(resource.getFile());
}
}

View File

@ -1,4 +1,4 @@
package test.kar.karusic;
package test.atriasoft.karusic;
import org.junit.jupiter.api.extension.ConditionEvaluationResult;
import org.junit.jupiter.api.extension.ExecutionCondition;

View File

@ -0,0 +1,59 @@
package test.atriasoft.karusic;
import org.atriasoft.archidata.exception.RESTErrorResponseException;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.archidata.tools.RESTApi;
import org.atriasoft.karusic.api.HealthCheck.HealthResult;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestHealthCheck {
private final static Logger LOGGER = LoggerFactory.getLogger(TestHealthCheck.class);
static WebLauncherTest webInterface = null;
static RESTApi api = null;
@BeforeAll
public static void configureWebServer() throws Exception {
ConfigureDb.configure();
LOGGER.info("configure server ...");
webInterface = new WebLauncherTest();
LOGGER.info("Start REST (BEGIN)");
webInterface.process();
LOGGER.info("Start REST (DONE)");
api = new RESTApi(ConfigBaseVariable.apiAdress);
api.setToken(Common.ADMIN_TOKEN);
}
@AfterAll
public static void stopWebServer() throws Exception {
LOGGER.info("Kill the web server");
webInterface.stop();
webInterface = null;
ConfigureDb.clear();
}
@Order(1)
@Test
public void checkHealthCheck() throws Exception {
final HealthResult result = api.request("health_check").get().fetch(HealthResult.class);
Assertions.assertEquals(result.value(), "alive and kicking");
}
@Order(2)
@Test
public void checkHealthCheckWrongAPI() throws Exception {
Assertions.assertThrows(RESTErrorResponseException.class, () -> api.request("health_check_kaboom").get().fetch());
}
}

View File

@ -0,0 +1,115 @@
package test.atriasoft.karusic;
import java.io.File;
import java.io.IOException;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.archidata.tools.RESTApi;
import org.atriasoft.karusic.model.Track;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestTrack {
private final static Logger LOGGER = LoggerFactory.getLogger(TestTrack.class);
public final static String ENDPOINT_NAME = "track";
public final static String ENDPOINT_DATA_NAME = "data";
static WebLauncherTest webInterface = null;
static RESTApi api = null;
@BeforeAll
public static void configureWebServer() throws Exception {
ConfigureDb.configure();
LOGGER.info("configure server ...");
webInterface = new WebLauncherTest();
LOGGER.info("Create BDD");
webInterface.migrateDB();
LOGGER.info("Start REST (BEGIN)");
webInterface.process();
LOGGER.info("Start REST (DONE)");
api = new RESTApi(ConfigBaseVariable.apiAdress);
api.setToken(Common.ADMIN_TOKEN);
}
@AfterAll
public static void stopWebServer() throws Exception {
LOGGER.info("Kill the web server");
webInterface.stop();
webInterface = null;
ConfigureDb.clear();
}
public static boolean compareResponseWithFile(final byte[] responseBody, final File file) throws IOException {
final byte[] fileBytes = Files.readAllBytes(file.toPath());
if (responseBody == null && fileBytes == null) {
return true;
}
if (responseBody == null || fileBytes == null) {
return false;
}
if (responseBody.length != fileBytes.length) {
LOGGER.error("The data have not the same size: {} != {}(ref)", responseBody.length, fileBytes.length);
return false;
}
for (int iii = 0; iii < responseBody.length; iii++) {
if (responseBody[iii] != fileBytes[iii]) {
LOGGER.error("Detect error at the {}/{} element", iii, responseBody.length);
return false;
}
}
return true;
}
@Order(1)
@Test
public void createTrack() throws Exception {
final File dataToUpload = ResourceUtils.getResourceFile("icon-192x192.png");
final Track data = new Track();
data.name = "test track";
data.description = "My track description";
final Map<String, Object> multipart = new HashMap<>();
multipart.put("title", data.name);
multipart.put("genderId", null);
multipart.put("artistId", null);
multipart.put("albumId", null);
multipart.put("trackId", 9);
multipart.put("file", dataToUpload);
final Track inserted = api.request(TestTrack.ENDPOINT_NAME, "upload").post().bodyMultipart(multipart).fetch(Track.class);
Assertions.assertNotNull(inserted);
Assertions.assertNotNull(inserted.oid);
// Assertions.assertTrue(inserted.oid >= 0);
Assertions.assertNull(inserted.updatedAt);
Assertions.assertNull(inserted.createdAt);
Assertions.assertNull(inserted.deleted);
Assertions.assertNotNull(inserted.name);
Assertions.assertEquals(data.name, inserted.name);
Assertions.assertNotNull(inserted.dataId);
// Retrieve Data:
final HttpResponse<byte[]> retreiveData = api.request(TestTrack.ENDPOINT_DATA_NAME, inserted.dataId.toString()).get().fetchByte();
Assertions.assertNotNull(retreiveData);
Assertions.assertEquals(200, retreiveData.statusCode());
Assertions.assertEquals("11999", retreiveData.headers().firstValue("content-length").orElse(null));
final String contentType = retreiveData.headers().firstValue("content-type").orElse(null);
Assertions.assertEquals("image/png", contentType);
Assertions.assertTrue(compareResponseWithFile(retreiveData.body(), dataToUpload));
}
}

View File

@ -0,0 +1,12 @@
package test.atriasoft.karusic;
import org.atriasoft.karusic.WebLauncher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class WebLauncherTest extends WebLauncher {
final private static Logger LOGGER = LoggerFactory.getLogger(WebLauncherTest.class);
public WebLauncherTest() {}
}

View File

@ -1,250 +0,0 @@
package test.kar.karusic;
import java.util.Map;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.kar.archidata.exception.RESTErrorResponseExeption;
import org.kar.archidata.model.GetToken;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.JWTWrapper;
import org.kar.archidata.tools.RESTApi;
import org.kar.karusic.api.HealthCheck.HealthResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.nimbusds.jwt.JWTClaimsSet;
@ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestBase {
private final static Logger LOGGER = LoggerFactory.getLogger(TestBase.class);
static WebLauncherTest webInterface = null;
static RESTApi api = null;
public void login(final String login, final String password) {
try {
final GetToken token = api.post(GetToken.class, "users/get_token", DataGetToken.generate(login, "v1", "202515252", password));
api.setToken(token.jwt());
} catch (final Exception ex) {
Assertions.fail("Can not get Authentication for '" + login + "' ==> " + ex.getMessage());
}
}
public void loginAdmin() {
login("karadmin", "adminA@666");
}
@BeforeAll
public static void configureWebServer() throws Exception {
LOGGER.info("configure server ...");
webInterface = new WebLauncherTest();
LOGGER.info("Create DB");
try {
webInterface.migrateDB();
} catch (final Exception ex) {
ex.printStackTrace();
LOGGER.error("Detect an error: {}", ex.getMessage());
}
LOGGER.info("Start REST (BEGIN)");
webInterface.process();
LOGGER.info("Start REST (DONE)");
api = new RESTApi(ConfigBaseVariable.apiAdress);
}
@AfterAll
public static void stopWebServer() throws InterruptedException {
LOGGER.info("Kill the web server");
webInterface = null;
// TODO: do it better...
}
@Order(1)
@Test
//@RepeatedTest(10)
public void checkHealthCheck() throws Exception {
final HealthResult result = api.get(HealthResult.class, "health_check");
Assertions.assertEquals(result.value(), "alive and kicking");
}
@Order(2)
@Test
public void checkHealthCheckWrongAPI() throws Exception {
Assertions.assertThrows(RESTErrorResponseExeption.class, () -> api.get(HealthResult.class, "health_checks"));
}
@Order(3)
@Test
public void firstUserConnect() throws Exception {
final GetToken result = api.post(GetToken.class, "users/get_token", DataGetToken.generate("karadmin", "v1", "202515252", "adminA@666"));
final String[] splitted = result.jwt().split("\\.");
Assertions.assertEquals(3, splitted.length);
final String authorization = result.jwt();
LOGGER.debug(" validate token : " + authorization);
// Note with local access we get the internal key of the system.
final JWTClaimsSet ret = JWTWrapper.validateToken(authorization, "KarAuth", null);
// check the token is valid !!! (signed and coherent issuer...
Assertions.assertNotNull(ret);
// check userID
final String userUID = ret.getSubject();
final long id = Long.parseLong(userUID);
Assertions.assertEquals(1, id);
final String name = (String) ret.getClaim("login");
Assertions.assertEquals("karadmin", name);
final Object rowRight = ret.getClaim("right");
Assertions.assertNotNull(rowRight);
final Map<String, Map<String, Object>> rights = (Map<String, Map<String, Object>>) ret.getClaim("right");
// Check if the element contain the basic keys:
Assertions.assertEquals(rights.size(), 1);
Assertions.assertTrue(rights.containsKey("karusic"));
final Map<String, Object> applRight = rights.get("karusic");
//logger.error("full right: {}", applRight);
Assertions.assertEquals(applRight.size(), 2);
Assertions.assertTrue(applRight.containsKey("ADMIN"));
Assertions.assertEquals(true, applRight.get("ADMIN"));
Assertions.assertTrue(applRight.containsKey("USER"));
Assertions.assertEquals(true, applRight.get("USER"));
//logger.debug("request user: '{}' right: '{}' row='{}'", userUID, applRight, rowRight);
//Assertions.assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9", splitted[0]);
//Assertions.assertEquals("eyJzdWIiOiIwIiwiYXBwbGljYXRpb24iOiJrYXJzbyIsImlzcyI6IkthckF1dGgiLCJyaWdodCI6eyJrYXJzbyI6eyJBRE1JTiI6dHJ1ZSwiVVNFUiI6dHJ1ZX19LCJsb2dpbiI6ImthcmFkbWluIiwiZXhwIjoxNjg0MTk5MTkzLCJpYXQiOjE2ODI3NTU0MjV9", splitted[1]);
// TODO ... Assertions.assertEquals("????", splitted[2]);
}
public void checkFail(final String type, final String urlOffset, final int errorStatus) {
checkFail(type, urlOffset, errorStatus, null);
}
public void checkFail(final String type, final String urlOffset, final int errorStatus, final String data) {
LOGGER.info("Test API: url={} urlOffset={}", type, urlOffset);
try {
if ("GET".equals(type)) {
api.get(String.class, urlOffset);
} else if ("POST".equals(type)) {
api.post(String.class, urlOffset, data);
} else if ("PUT".equals(type)) {
api.put(String.class, urlOffset, data);
} else if ("DELETE".equals(type)) {
api.delete(String.class, urlOffset);
}
Assertions.fail("Request on URL does not fail as expected: '" + type + "' url='" + urlOffset + "'");
} catch (final RESTErrorResponseExeption ex) {
if (errorStatus != ex.status) {
LOGGER.error("Fail in test with the wrong return errors: {}", ex.toString());
}
Assertions.assertEquals(errorStatus, ex.status);
} catch (final Exception ex) {
LOGGER.error("Unexpected throw error: {}", ex);
Assertions.fail("Unexpected throws...");
}
}
public void checkWork(final String type, final String urlOffset) {
checkWork(type, urlOffset, null);
}
public void checkWork(final String type, final String urlOffset, final String data) {
LOGGER.info("Test API: url={} urlOffset={}", type, urlOffset);
try {
if ("GET".equals(type)) {
api.get(String.class, urlOffset);
} else if ("POST".equals(type)) {
api.post(String.class, urlOffset, data);
} else if ("PUT".equals(type)) {
api.put(String.class, urlOffset, data);
} else if ("DELETE".equals(type)) {
api.delete(String.class, urlOffset);
}
//Assertions.fail("Request on URL does not fail as expected: '" + type + "' url='" + urlOffset + "'");
} catch (final RESTErrorResponseExeption ex) {
Assertions.fail("Must not fail ... " + ex.toString());
} catch (final Exception ex) {
LOGGER.error("Unexpected throw error: {}", ex);
Assertions.fail("Unexpected throws...");
}
}
@Order(4)
@Test
public void checkUnAuthorizedAPI() throws Exception {
// /application/
checkFail("GET", "application/", 401);
checkFail("POST", "application/", 401, "{}");
checkFail("PUT", "application/", 405, "{}"); // does not exist
checkFail("DELETE", "application/", 405); // does not exist
// /application/{id}
checkFail("GET", "application/0", 401);
checkFail("PUT", "application/0", 401, "{}");
checkFail("POST", "application/0", 405, "{}");
checkFail("DELETE", "application/0", 401);
// /application/{id}/*
checkFail("GET", "application/0/users", 401);
// /application/*
checkFail("GET", "application/small", 401);
checkFail("GET", "application/get_token", 401);
checkFail("GET", "application/return", 401);
// /application_token/ section:
checkFail("GET", "application_token/0", 401);
checkFail("DELETE", "application_token/0/5", 401);
checkFail("DELETE", "application_token/0/create", 401);
// /front/*
checkFail("GET", "front", 404); // no index in test section
// health check
checkWork("GET", "health_check");
// public_key (only application)
checkFail("GET", "public_key", 401);
checkFail("GET", "public_key/pem", 401);
// /right
checkFail("GET", "right", 401);
checkFail("POST", "right", 401, "{}");
checkFail("GET", "right/0", 401);
checkFail("PUT", "right/0", 401, "{}");
checkFail("DELETE", "right/0", 401);
// /system_config
checkWork("GET", "system_config/is_sign_up_availlable");
checkFail("GET", "system_config/key/skjdfhkjsdhfkjsh", 401);
checkFail("PUT", "system_config/key/skjdfhkjsdhfkjsh", 401, "{}");
// /users
checkFail("GET", "users", 401);
checkFail("GET", "users/0", 401);
checkFail("POST", "users/0/application/0/link", 401, "{}");
checkFail("POST", "users/0/set_admin", 401, "{}");
checkFail("POST", "users/0/set_blocked", 401, "{}");
checkFail("POST", "users/create_new_user", 401, "{}");
checkFail("GET", "users/me", 401, "{}");
checkFail("POST", "users/password", 401, "{}");
checkWork("GET", "users/check_login?login=karadmin");
checkFail("GET", "users/check_login?login=jhkjhkjh", 404);
checkWork("GET", "users/check_email?email=admin@admin.ZZZ");
checkFail("GET", "users/check_email?email=ksjhdkjfhskjdh", 404);
// not testable : get_token
}
@Order(5)
@Test
public void testMeWithToken() throws Exception {
loginAdmin();
final String result = api.get(String.class, "users/me");
Assertions.assertEquals("{\"id\":1,\"login\":\"karadmin\"}", result);
}
}

View File

@ -1,28 +0,0 @@
package test.kar.karusic;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.karusic.WebLauncher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class WebLauncherTest extends WebLauncher {
final private static Logger LOGGER = LoggerFactory.getLogger(WebLauncherTest.class);
public WebLauncherTest() {
LOGGER.debug("Configure REST system");
// for local test:
ConfigBaseVariable.apiAdress = "http://127.0.0.1:12345/test/api/";
ConfigBaseVariable.dbPort = "3306";
// for the test we a in memory sqlite..
ConfigBaseVariable.dbType = "sqlite";
ConfigBaseVariable.dbHost = "memory";
// for test we need to connect all time the DB
ConfigBaseVariable.dbKeepConnected = "true";
ConfigBaseVariable.dbHost = "localhost";
ConfigBaseVariable.dbUser = "root";
ConfigBaseVariable.dbPassword = "ZERTYSDGFVHSDFGHJYZSDFGSQxfgsqdfgsqdrf4564654";
}
}

View File

@ -0,0 +1,56 @@
services:
kar_db_service:
image: mysql:latest
restart: always
environment:
- MYSQL_ROOT_PASSWORD=base_db_password
volumes:
- ./data:/var/lib/mysql
mem_limit: 300m
ports:
- 3906:3306
healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
timeout: 10s
retries: 5
# perform a 1 minute grace to let the DB to perform the initialization
start_period: 1m
start_interval: 1m
kar_mongodb_service:
image: mongo:latest
restart: always
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: base_db_password
ports:
- 27017:27017
volumes:
- ./dataMongo:/data/db
kar_adminer_service:
image: adminer:latest
restart: always
depends_on:
kar_db_service:
condition: service_healthy
links:
- kar_db_service:db
- kar_mongodb_service:dbm
ports:
- 4079:8080
mem_limit: 50m
mongo_express_service:
image: mongo-express
restart: always
ports:
- 4077:8081
links:
- kar_mongodb_service:db
environment:
ME_CONFIG_MONGODB_ADMINUSERNAME: root
ME_CONFIG_MONGODB_ADMINPASSWORD: base_db_password
ME_CONFIG_MONGODB_URL: mongodb://root:base_db_password@db:27017/
ME_CONFIG_BASICAUTH: false

View File

@ -1,12 +0,0 @@
# 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
# You can see what browsers were selected by your queries by running:
# npx browserslist
> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11 # For IE 9-11 support, remove 'not'.

View File

@ -1,13 +0,0 @@
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false

1
front/.env Normal file
View File

@ -0,0 +1 @@
NODE_ENV=development

2
front/.env.production Normal file
View File

@ -0,0 +1,2 @@
# URL for database connection
VITE_API_BASE_URL=karusic/api/

View File

@ -1,4 +0,0 @@
node_modules/*
build/*
out/*
dist/*

View File

@ -1,225 +0,0 @@
var OFF = 0, WARN = 1, ERROR = 2;
module.exports = {
'env': {
'browser': true,
'es2021': true,
},
'extends': [
'eslint:recommended',
],
'parser': '@typescript-eslint/parser',
'parserOptions': {
'ecmaVersion': 'latest',
'sourceType': 'module',
},
'plugins': [
'@typescript-eslint',
],
"rules": {
// Possible Errors (overrides from recommended set)
"no-extra-parens": ERROR,
"no-unexpected-multiline": ERROR,
// All JSDoc comments must be valid
"valid-jsdoc": [ OFF, {
"requireReturn": false,
"requireReturnDescription": false,
"requireParamDescription": true,
"prefer": {
"return": "returns"
}
}],
// Best Practices
// Allowed a getter without setter, but all setters require getters
"accessor-pairs": [ OFF, {
"getWithoutSet": false,
"setWithoutGet": true
}],
"block-scoped-var": WARN,
"consistent-return": OFF,
"curly": ERROR,
"default-case": WARN,
// the dot goes with the property when doing multiline
"dot-location": [ WARN, "property" ],
"dot-notation": WARN,
"eqeqeq": [ ERROR, "smart" ],
"guard-for-in": WARN,
"no-alert": ERROR,
"no-caller": ERROR,
"no-case-declarations": WARN,
"no-div-regex": WARN,
"no-else-return": WARN,
"no-empty-pattern": WARN,
"no-eq-null": ERROR,
"no-eval": ERROR,
"no-extend-native": ERROR,
"no-extra-bind": WARN,
"no-floating-decimal": WARN,
"no-implicit-coercion": [ WARN, {
"boolean": true,
"number": true,
"string": true
}],
"no-implied-eval": ERROR,
"no-invalid-this": ERROR,
"no-iterator": ERROR,
"no-labels": WARN,
"no-lone-blocks": WARN,
"no-loop-func": ERROR,
"no-magic-numbers": OFF,
"no-multi-spaces": ERROR,
"no-multi-str": WARN,
"no-native-reassign": ERROR,
"no-new-func": ERROR,
"no-new-wrappers": ERROR,
"no-new": ERROR,
"no-octal-escape": ERROR,
"no-param-reassign": ERROR,
"no-process-env": WARN,
"no-proto": ERROR,
"no-redeclare": ERROR,
"no-return-assign": ERROR,
"no-script-url": ERROR,
"no-self-compare": ERROR,
"no-throw-literal": ERROR,
"no-unused-expressions": ERROR,
"no-useless-call": ERROR,
"no-useless-concat": ERROR,
"no-void": WARN,
// Produce warnings when something is commented as TODO or FIXME
"no-warning-comments": [ WARN, {
"terms": [ "TODO", "FIXME" ],
"location": "start"
}],
"no-with": WARN,
"radix": WARN,
"vars-on-top": ERROR,
// Enforces the style of wrapped functions
"wrap-iife": [ ERROR, "outside" ],
"yoda": ERROR,
// Strict Mode - for ES6, never use strict.
"strict": [ ERROR, "never" ],
// Variables
"init-declarations": [ OFF, "always" ],
"no-catch-shadow": WARN,
"no-delete-var": ERROR,
"no-label-var": ERROR,
"no-shadow-restricted-names": ERROR,
"no-shadow": WARN,
// We require all vars to be initialized (see init-declarations)
// If we NEED a var to be initialized to undefined, it needs to be explicit
"no-undef-init": OFF,
"no-undef": ERROR,
"no-undefined": OFF,
"no-unused-vars": OFF,
// Disallow hoisting - let & const don't allow hoisting anyhow
"no-use-before-define": ERROR,
// Node.js and CommonJS
"callback-return": [ WARN, [ "callback", "next" ]],
"global-require": ERROR,
"handle-callback-err": WARN,
"no-mixed-requires": WARN,
"no-new-require": ERROR,
// Use path.concat instead
"no-path-concat": ERROR,
"no-process-exit": ERROR,
"no-restricted-modules": OFF,
"no-sync": WARN,
// ECMAScript 6 support
"arrow-body-style": [ ERROR, "always" ],
"arrow-parens": [ ERROR, "always" ],
"arrow-spacing": [ ERROR, { "before": true, "after": true }],
"constructor-super": ERROR,
"generator-star-spacing": [ ERROR, "before" ],
"no-confusing-arrow": ERROR,
"no-class-assign": ERROR,
"no-const-assign": ERROR,
"no-dupe-class-members": ERROR,
"no-this-before-super": ERROR,
"no-var": WARN,
"object-shorthand": [ WARN, "never" ],
"prefer-arrow-callback": WARN,
"prefer-spread": WARN,
"prefer-template": WARN,
"require-yield": ERROR,
// Stylistic - everything here is a warning because of style.
"array-bracket-spacing": [ WARN, "always" ],
"block-spacing": [ WARN, "always" ],
"brace-style": [ WARN, "1tbs", { "allowSingleLine": false } ],
"camelcase": WARN,
"comma-spacing": [ WARN, { "before": false, "after": true } ],
"comma-style": [ WARN, "last" ],
"computed-property-spacing": [ WARN, "never" ],
"consistent-this": [ WARN, "self" ],
"eol-last": WARN,
"func-names": WARN,
"func-style": [ WARN, "declaration" ],
"id-length": [ WARN, { "min": 2, "max": 32 } ],
"indent": [ WARN, 'tab' ],
"jsx-quotes": [ WARN, "prefer-double" ],
"linebreak-style": [ WARN, "unix" ],
"lines-around-comment": [ OFF, { "beforeBlockComment": true } ],
"max-depth": [ WARN, 8 ],
"max-len": [ WARN, 182 ],
"max-nested-callbacks": [ WARN, 8 ],
"max-params": [ WARN, 10 ],
"new-cap": OFF,
"new-parens": WARN,
"no-array-constructor": WARN,
"no-bitwise": OFF,
"no-continue": OFF,
"no-inline-comments": OFF,
"no-lonely-if": OFF,
"no-mixed-spaces-and-tabs": OFF,
"no-multiple-empty-lines": WARN,
"no-negated-condition": OFF,
"no-nested-ternary": WARN,
"no-new-object": WARN,
"no-plusplus": OFF,
"no-spaced-func": WARN,
"no-ternary": OFF,
"no-trailing-spaces": WARN,
"no-underscore-dangle": WARN,
"no-unneeded-ternary": WARN,
"object-curly-spacing": [ WARN, "always" ],
"one-var": OFF,
"operator-assignment": [ WARN, "never" ],
"operator-linebreak": [ WARN, "after" ],
"padded-blocks": [ WARN, "never" ],
"quote-props": [ WARN, "consistent-as-needed" ],
"quotes": [ WARN, "single" ],
"require-jsdoc": [ OFF, {
"require": {
"FunctionDeclaration": true,
"MethodDefinition": true,
"ClassDeclaration": false
}
}],
"semi-spacing": [ WARN, { "before": false, "after": true }],
"semi": [ ERROR, "always" ],
"sort-vars": OFF,
"keyword-spacing": [WARN, {
"overrides": {
"if": { "after": false },
"for": { "after": false },
"while": { "after": false },
"static": { "after": false },
"as": { "after": false }
}
}],
"space-before-blocks": [ WARN, "always" ],
"space-before-function-paren": [ WARN, "never" ],
"space-in-parens": [ WARN, "never" ],
"space-infix-ops": [ WARN, { "int32Hint": true } ],
"space-unary-ops": ERROR,
"spaced-comment": [ WARN, "always" ],
"wrap-regex": WARN,
},
};

3
front/.gitignore vendored
View File

@ -1,3 +0,0 @@
/node_modules/
/.angular/
/.idea/

27
front/.storybook/main.ts Normal file
View File

@ -0,0 +1,27 @@
import type { StorybookConfig } from '@storybook/react-vite';
const config: StorybookConfig = {
framework: {
name: '@storybook/react-vite',
options: {},
},
core: {
disableTelemetry: true,
builder: '@storybook/builder-vite',
},
stories: ['../src/**/*.@(mdx|stories.@(js|jsx|ts|tsx))'],
addons: ['@storybook/addon-links', '@storybook/addon-essentials'],
staticDirs: ['../public'],
typescript: {
reactDocgen: false,
},
docs: {},
};
export default config;

View File

@ -0,0 +1,16 @@
<style>
html {
background: transparent !important;
}
.docs-story > :first-child {
padding: 0;
}
.docs-story > * {
background: transparent !important;
}
#root #start-ui-storybook-wrapper {
min-height: 100vh;
}
</style>

View File

@ -0,0 +1,34 @@
import React from 'react';
import { Box } from '@chakra-ui/react';
import { ChakraProvider } from '@chakra-ui/react';
import { MemoryRouter } from 'react-router-dom';
import { ColorModeProvider } from '../src/components/ui/color-mode';
import { Toaster } from '../src/components/ui/toaster';
import { systemTheme } from '../src/theme/theme';
// .
const DocumentationWrapper = ({ children }) => {
return (
<Box id="start-ui-storybook-wrapper" p="4" pb="8" flex="1">
{children}
</Box>
);
};
export const decorators = [
(Story, context) => (
<ColorModeProvider>
<ChakraProvider value={systemTheme}>
{/* Using MemoryRouter to avoid route clashing with Storybook */}
<MemoryRouter>
<DocumentationWrapper>
<Story {...context} />
</DocumentationWrapper>
</MemoryRouter>
<Toaster />
</ChakraProvider>
</ColorModeProvider>
),
];

View File

@ -1,35 +0,0 @@
# base image
FROM node:lts as build
# add `/application/node_modules/.bin` to $PATH
ENV PATH /application/node_modules/.bin:$PATH
ADD package-lock.json /application/
ADD package.json /application/
#ADD browserslist /application/
ADD karma.conf.js /application/
ADD protractor.conf.js /application/
WORKDIR /application/
# install and cache app dependencies
RUN npm install
ADD e2e /application/e2e
ADD tsconfig.json /application/
ADD tslint.json /application/
ADD angular.json /application/
ADD src /application/src
# generate build
RUN ng build --output-path=dist --configuration=production --base-href=/karideo/ --deploy-url=/karideo/
############
### prod ###
############
# base image
FROM httpd:latest
# copy artifact build from the 'build environment'
COPY --from=build /application/dist /usr/local/apache2/htdocs/
COPY httpd/httpd.conf /usr/local/apache2/conf/httpd.conf

View File

@ -1,24 +0,0 @@
# base image
FROM node:latest
ADD src /application/src
ADD e2e /application/e2e
ADD package-lock.json /application/
ADD package.json /application/
ADD angular.json /application/
ADD browserslist /application/
ADD karma.conf.js /application/
ADD protractor.conf.js /application/
ADD tsconfig.json /application/
ADD tslint.json /application/
WORKDIR /application/
# add `/app/node_modules/.bin` to $PATH
ENV PATH /app/node_modules/.bin:$PATH
# install and cache app dependencies
RUN npm install
# start app
CMD ["npx", "ng", "serve", "--host", "0.0.0.0"]

2
front/LICENSE Normal file
View File

@ -0,0 +1,2 @@
Proprietary
@copyright Edouard Dupin 2024

View File

@ -1,134 +0,0 @@
{
"$schema" : "./node_modules/@angular/cli/lib/config/schema.json",
"version" : 1,
"newProjectRoot" : "projects",
"defaultProject" : "karusic",
"projects" : {
"karusic" : {
"root" : "",
"sourceRoot" : "src",
"projectType" : "application",
"architect" : {
"build" : {
"builder" : "@angular-devkit/build-angular:browser",
"options" : {
"outputPath" : "dist",
"index" : "src/index.html",
"main" : "src/main.ts",
"tsConfig" : "src/tsconfig.app.json",
"polyfills" : "src/polyfills.ts",
"assets" : [ "src/assets", "src/favicon.ico" ],
"styles" : [ "src/styles.less", "src/generic_page.less", "src/theme.color.blue.less", "src/theme.checkbox.less", "src/theme.modal.less" ],
"scripts" : [ ]
},
"configurations" : {
"production" : {
"optimization" : true,
"outputHashing" : "all",
"sourceMap" : false,
"namedChunks" : false,
"aot" : true,
"extractLicenses" : true,
"vendorChunk" : false,
"buildOptimizer" : true,
"fileReplacements" : [ {
"replace" : "src/environments/environment.ts",
"with" : "src/environments/environment.prod.ts"
} ]
},
"develop" : {
"optimization" : false,
"outputHashing" : "none",
"sourceMap" : true,
"namedChunks" : true,
"aot" : true,
"extractLicenses" : true,
"vendorChunk" : true,
"buildOptimizer" : false
}
}
},
"serve" : {
"builder" : "@angular-devkit/build-angular:dev-server",
"options" : {
"browserTarget" : "karusic:build"
},
"configurations" : {
"production" : {
"browserTarget" : "karusic:build:production"
},
"develop" : {
"browserTarget" : "karusic:build:develop"
}
}
},
"extract-i18n" : {
"builder" : "@angular-devkit/build-angular:extract-i18n",
"options" : {
"browserTarget" : "karusic:build"
}
},
"test" : {
"builder" : "@angular-devkit/build-angular:karma",
"options" : {
"main" : "src/test.ts",
"karmaConfig" : "./karma.conf.js",
"polyfills" : "src/polyfills.ts",
"tsConfig" : "src/tsconfig.spec.json",
"scripts" : [ ],
"styles" : [ "src/styles.less", "src/generic_page.less", "src/theme.color.blue.less", "src/theme.checkbox.less", "src/theme.modal.less" ],
"assets" : [ "src/assets", "src/favicon.ico" ]
}
},
"lint" : {
"builder" : "@angular-eslint/builder:lint",
"options" : {
"fix": true,
"eslintConfig": ".eslintrc.js",
"lintFilePatterns": [
"src/**/*.spec.ts",
"src/**/*.ts"
]
}
},
"TTTTTTlint" : {
"builder" : "@angular-devkit/build-angular:tslint",
"options" : {
"tsConfig" : [ "src/tsconfig.app.json", "src/tsconfig.spec.json" ],
"exclude" : [ "**/node_modules/**" ]
}
}
}
},
"karusic-e2e" : {
"root" : "e2e",
"sourceRoot" : "e2e",
"projectType" : "application",
"architect" : {
"e2e" : {
"builder" : "@angular-devkit/build-angular:protractor",
"options" : {
"protractorConfig" : "./protractor.conf.js",
"devServerTarget" : "karusic:serve"
}
},
"lint" : {
"builder" : "@angular-devkit/build-angular:tslint",
"options" : {
"tsConfig" : [ "e2e/tsconfig.e2e.json" ],
"exclude" : [ "**/node_modules/**" ]
}
}
}
}
},
"schematics" : {
"@schematics/angular:component" : {
"prefix" : "app",
"style" : "less"
},
"@schematics/angular:directive" : {
"prefix" : "app"
}
}
}

10637
front/config sample.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +0,0 @@
version: '3'
services:
karideo_service:
build: .
restart: always
image: yui.heero/karideo
container_name: karideo
ports:
#- 15081:4200
- 15081:80

View File

@ -1,14 +0,0 @@
import { AppPage } from './app.po';
describe('karusic App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
it('should display welcome message', () => {
page.navigateTo();
expect(page.getParagraphText()).toEqual('Welcome to app!');
});
});

View File

@ -1,11 +0,0 @@
import { browser, by, element } from 'protractor';
export class AppPage {
navigateTo() {
return browser.get('/');
}
getParagraphText() {
return element(by.css('app-root h1')).getText();
}
}

View File

@ -1,14 +0,0 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"baseUrl": "./",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"jasminewd2",
"node"
]
}
}

View File

@ -1,541 +0,0 @@
#
# This is the main Apache HTTP server configuration file. It contains the
# configuration directives that give the server its instructions.
# See <URL:http://httpd.apache.org/docs/2.4/> for detailed information.
# In particular, see
# <URL:http://httpd.apache.org/docs/2.4/mod/directives.html>
# for a discussion of each configuration directive.
#
# Do NOT simply read the instructions in here without understanding
# what they do. They're here only as hints or reminders. If you are unsure
# consult the online docs. You have been warned.
#
# Configuration and logfile names: If the filenames you specify for many
# of the server's control files begin with "/" (or "drive:/" for Win32), the
# server will use that explicit path. If the filenames do *not* begin
# with "/", the value of ServerRoot is prepended -- so "logs/access_log"
# with ServerRoot set to "/usr/local/apache2" will be interpreted by the
# server as "/usr/local/apache2/logs/access_log", whereas "/logs/access_log"
# will be interpreted as '/logs/access_log'.
#
# ServerRoot: The top of the directory tree under which the server's
# configuration, error, and log files are kept.
#
# Do not add a slash at the end of the directory path. If you point
# ServerRoot at a non-local disk, be sure to specify a local disk on the
# Mutex directive, if file-based mutexes are used. If you wish to share the
# same ServerRoot for multiple httpd daemons, you will need to change at
# least PidFile.
#
ServerRoot "/usr/local/apache2"
#
# Mutex: Allows you to set the mutex mechanism and mutex file directory
# for individual mutexes, or change the global defaults
#
# Uncomment and change the directory if mutexes are file-based and the default
# mutex file directory is not on a local disk or is not appropriate for some
# other reason.
#
# Mutex default:logs
#
# Listen: Allows you to bind Apache to specific IP addresses and/or
# ports, instead of the default. See also the <VirtualHost>
# directive.
#
# Change this to Listen on specific IP addresses as shown below to
# prevent Apache from glomming onto all bound IP addresses.
#
Listen 80
Listen 443
#
# Dynamic Shared Object (DSO) Support
#
# To be able to use the functionality of a module which was built as a DSO you
# have to place corresponding `LoadModule' lines at this location so the
# directives contained in it are actually available _before_ they are used.
# Statically compiled modules (those listed by `httpd -l') do not need
# to be loaded here.
#
# Example:
# LoadModule foo_module modules/mod_foo.so
#
LoadModule mpm_event_module modules/mod_mpm_event.so
#LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
#LoadModule mpm_worker_module modules/mod_mpm_worker.so
LoadModule authn_file_module modules/mod_authn_file.so
#LoadModule authn_dbm_module modules/mod_authn_dbm.so
#LoadModule authn_anon_module modules/mod_authn_anon.so
#LoadModule authn_dbd_module modules/mod_authn_dbd.so
#LoadModule authn_socache_module modules/mod_authn_socache.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_user_module modules/mod_authz_user.so
#LoadModule authz_dbm_module modules/mod_authz_dbm.so
#LoadModule authz_owner_module modules/mod_authz_owner.so
#LoadModule authz_dbd_module modules/mod_authz_dbd.so
LoadModule authz_core_module modules/mod_authz_core.so
#LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
#LoadModule authnz_fcgi_module modules/mod_authnz_fcgi.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule auth_basic_module modules/mod_auth_basic.so
#LoadModule auth_form_module modules/mod_auth_form.so
#LoadModule auth_digest_module modules/mod_auth_digest.so
#LoadModule allowmethods_module modules/mod_allowmethods.so
#LoadModule isapi_module modules/mod_isapi.so
#LoadModule file_cache_module modules/mod_file_cache.so
#LoadModule cache_module modules/mod_cache.so
#LoadModule cache_disk_module modules/mod_cache_disk.so
#LoadModule cache_socache_module modules/mod_cache_socache.so
#LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
#LoadModule socache_dbm_module modules/mod_socache_dbm.so
#LoadModule socache_memcache_module modules/mod_socache_memcache.so
#LoadModule watchdog_module modules/mod_watchdog.so
#LoadModule macro_module modules/mod_macro.so
#LoadModule dbd_module modules/mod_dbd.so
#LoadModule bucketeer_module modules/mod_bucketeer.so
#LoadModule dumpio_module modules/mod_dumpio.so
#LoadModule echo_module modules/mod_echo.so
#LoadModule example_hooks_module modules/mod_example_hooks.so
#LoadModule case_filter_module modules/mod_case_filter.so
#LoadModule case_filter_in_module modules/mod_case_filter_in.so
#LoadModule example_ipc_module modules/mod_example_ipc.so
#LoadModule buffer_module modules/mod_buffer.so
#LoadModule data_module modules/mod_data.so
#LoadModule ratelimit_module modules/mod_ratelimit.so
LoadModule reqtimeout_module modules/mod_reqtimeout.so
#LoadModule ext_filter_module modules/mod_ext_filter.so
#LoadModule request_module modules/mod_request.so
#LoadModule include_module modules/mod_include.so
LoadModule filter_module modules/mod_filter.so
#LoadModule reflector_module modules/mod_reflector.so
#LoadModule substitute_module modules/mod_substitute.so
#LoadModule sed_module modules/mod_sed.so
#LoadModule charset_lite_module modules/mod_charset_lite.so
#LoadModule deflate_module modules/mod_deflate.so
LoadModule xml2enc_module modules/mod_xml2enc.so
LoadModule proxy_html_module modules/mod_proxy_html.so
LoadModule mime_module modules/mod_mime.so
#LoadModule ldap_module modules/mod_ldap.so
LoadModule log_config_module modules/mod_log_config.so
#LoadModule log_debug_module modules/mod_log_debug.so
#LoadModule log_forensic_module modules/mod_log_forensic.so
#LoadModule logio_module modules/mod_logio.so
#LoadModule lua_module modules/mod_lua.so
LoadModule env_module modules/mod_env.so
#LoadModule mime_magic_module modules/mod_mime_magic.so
#LoadModule cern_meta_module modules/mod_cern_meta.so
#LoadModule expires_module modules/mod_expires.so
LoadModule headers_module modules/mod_headers.so
#LoadModule ident_module modules/mod_ident.so
#LoadModule usertrack_module modules/mod_usertrack.so
#LoadModule unique_id_module modules/mod_unique_id.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
#LoadModule remoteip_module modules/mod_remoteip.so
LoadModule proxy_module modules/mod_proxy.so
#LoadModule proxy_connect_module modules/mod_proxy_connect.so
#LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
LoadModule proxy_http_module modules/mod_proxy_http.so
#LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
#LoadModule proxy_scgi_module modules/mod_proxy_scgi.so
#LoadModule proxy_uwsgi_module modules/mod_proxy_uwsgi.so
#LoadModule proxy_fdpass_module modules/mod_proxy_fdpass.so
#LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
#LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
#LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
#LoadModule proxy_express_module modules/mod_proxy_express.so
#LoadModule proxy_hcheck_module modules/mod_proxy_hcheck.so
#LoadModule session_module modules/mod_session.so
#LoadModule session_cookie_module modules/mod_session_cookie.so
#LoadModule session_crypto_module modules/mod_session_crypto.so
#LoadModule session_dbd_module modules/mod_session_dbd.so
#LoadModule slotmem_shm_module modules/mod_slotmem_shm.so
#LoadModule slotmem_plain_module modules/mod_slotmem_plain.so
LoadModule ssl_module modules/mod_ssl.so
#LoadModule optional_hook_export_module modules/mod_optional_hook_export.so
#LoadModule optional_hook_import_module modules/mod_optional_hook_import.so
#LoadModule optional_fn_import_module modules/mod_optional_fn_import.so
#LoadModule optional_fn_export_module modules/mod_optional_fn_export.so
#LoadModule dialup_module modules/mod_dialup.so
#LoadModule http2_module modules/mod_http2.so
#LoadModule proxy_http2_module modules/mod_proxy_http2.so
#LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so
#LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so
#LoadModule lbmethod_bybusyness_module modules/mod_lbmethod_bybusyness.so
#LoadModule lbmethod_heartbeat_module modules/mod_lbmethod_heartbeat.so
LoadModule unixd_module modules/mod_unixd.so
#LoadModule heartbeat_module modules/mod_heartbeat.so
#LoadModule heartmonitor_module modules/mod_heartmonitor.so
#LoadModule dav_module modules/mod_dav.so
LoadModule status_module modules/mod_status.so
LoadModule autoindex_module modules/mod_autoindex.so
#LoadModule asis_module modules/mod_asis.so
#LoadModule info_module modules/mod_info.so
#LoadModule suexec_module modules/mod_suexec.so
<IfModule !mpm_prefork_module>
#LoadModule cgid_module modules/mod_cgid.so
</IfModule>
<IfModule mpm_prefork_module>
#LoadModule cgi_module modules/mod_cgi.so
</IfModule>
#LoadModule dav_fs_module modules/mod_dav_fs.so
#LoadModule dav_lock_module modules/mod_dav_lock.so
#LoadModule vhost_alias_module modules/mod_vhost_alias.so
#LoadModule negotiation_module modules/mod_negotiation.so
LoadModule dir_module modules/mod_dir.so
#LoadModule imagemap_module modules/mod_imagemap.so
#LoadModule actions_module modules/mod_actions.so
#LoadModule speling_module modules/mod_speling.so
#LoadModule userdir_module modules/mod_userdir.so
LoadModule alias_module modules/mod_alias.so
LoadModule rewrite_module modules/mod_rewrite.so
<IfModule unixd_module>
#
# If you wish httpd to run as a different user or group, you must run
# httpd as root initially and it will switch.
#
# User/Group: The name (or #number) of the user/group to run httpd as.
# It is usually good practice to create a dedicated user and group for
# running httpd, as with most system services.
#
User daemon
Group daemon
</IfModule>
# 'Main' server configuration
#
# The directives in this section set up the values used by the 'main'
# server, which responds to any requests that aren't handled by a
# <VirtualHost> definition. These values also provide defaults for
# any <VirtualHost> containers you may define later in the file.
#
# All of these directives may appear inside <VirtualHost> containers,
# in which case these default settings will be overridden for the
# virtual host being defined.
#
#
# ServerAdmin: Your address, where problems with the server should be
# e-mailed. This address appears on some server-generated pages, such
# as error documents. e.g. admin@your-domain.com
#
ServerAdmin yui.heero@gmail.com
#
# ServerName gives the name and port that the server uses to identify itself.
# This can often be determined automatically, but we recommend you specify
# it explicitly to prevent problems during startup.
#
# If your host doesn't have a registered DNS name, enter its IP address here.
#
#ServerName www.example.com:80
#
# Deny access to the entirety of your server's filesystem. You must
# explicitly permit access to web content directories in other
# <Directory> blocks below.
#
<Directory />
AllowOverride none
Require all denied
</Directory>
# intermediate configuration, tweak to your needs
SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
SSLHonorCipherOrder on
#
# Note that from this point forward you must specifically allow
# particular features to be enabled - so if something's not working as
# you might expect, make sure that you have specifically enabled it
# below.
#
#
# DocumentRoot: The directory out of which you will serve your
# documents. By default, all requests are taken from this directory, but
# symbolic links and aliases may be used to point to other locations.
#
<VirtualHost *:80>
ServerName my-app
DocumentRoot "/usr/local/apache2/htdocs"
<Directory "/usr/local/apache2/htdocs">
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
RewriteEngine on
# Don't rewrite files or directories
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# Rewrite everything else to index.html to allow HTML5 state links
RewriteRule ^ index.html [L]
</Directory>
</VirtualHost>
#
# DirectoryIndex: sets the file that Apache will serve if a directory
# is requested.
#
<IfModule dir_module>
DirectoryIndex index.html
</IfModule>
#
# The following lines prevent .htaccess and .htpasswd files from being
# viewed by Web clients.
#
<Files ".ht*">
Require all denied
</Files>
#
# ErrorLog: The location of the error log file.
# If you do not specify an ErrorLog directive within a <VirtualHost>
# container, error messages relating to that virtual host will be
# logged here. If you *do* define an error logfile for a <VirtualHost>
# container, that host's errors will be logged there and not here.
#
ErrorLog /proc/self/fd/2
#
# LogLevel: Control the number of messages logged to the error_log.
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
#
LogLevel warn
<IfModule log_config_module>
#
# The following directives define some format nicknames for use with
# a CustomLog directive (see below).
#
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
<IfModule logio_module>
# You need to enable mod_logio.c to use %I and %O
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
</IfModule>
#
# The location and format of the access logfile (Common Logfile Format).
# If you do not define any access logfiles within a <VirtualHost>
# container, they will be logged here. Contrariwise, if you *do*
# define per-<VirtualHost> access logfiles, transactions will be
# logged therein and *not* in this file.
#
CustomLog /proc/self/fd/1 common
#
# If you prefer a logfile with access, agent, and referer information
# (Combined Logfile Format) you can use the following directive.
#
#CustomLog "logs/access_log" combined
</IfModule>
<IfModule alias_module>
#
# Redirect: Allows you to tell clients about documents that used to
# exist in your server's namespace, but do not anymore. The client
# will make a new request for the document at its new location.
# Example:
# Redirect permanent /foo http://www.example.com/bar
#
# Alias: Maps web paths into filesystem paths and is used to
# access content that does not live under the DocumentRoot.
# Example:
# Alias /webpath /full/filesystem/path
#
# If you include a trailing / on /webpath then the server will
# require it to be present in the URL. You will also likely
# need to provide a <Directory> section to allow access to
# the filesystem path.
#
# ScriptAlias: This controls which directories contain server scripts.
# ScriptAliases are essentially the same as Aliases, except that
# documents in the target directory are treated as applications and
# run by the server when requested rather than as documents sent to the
# client. The same rules about trailing "/" apply to ScriptAlias
# directives as to Alias.
#
ScriptAlias /cgi-bin/ "/usr/local/apache2/cgi-bin/"
</IfModule>
<IfModule cgid_module>
#
# ScriptSock: On threaded servers, designate the path to the UNIX
# socket used to communicate with the CGI daemon of mod_cgid.
#
#Scriptsock cgisock
</IfModule>
#
# "/usr/local/apache2/cgi-bin" should be changed to whatever your ScriptAliased
# CGI directory exists, if you have that configured.
#
<Directory "/usr/local/apache2/cgi-bin">
AllowOverride None
Options None
Require all granted
</Directory>
<IfModule headers_module>
#
# Avoid passing HTTP_PROXY environment to CGI's on this or any proxied
# backend servers which have lingering "httpoxy" defects.
# 'Proxy' request header is undefined by the IETF, not listed by IANA
#
RequestHeader unset Proxy early
</IfModule>
<IfModule mime_module>
#
# TypesConfig points to the file containing the list of mappings from
# filename extension to MIME-type.
#
TypesConfig conf/mime.types
#
# AddType allows you to add to or override the MIME configuration
# file specified in TypesConfig for specific file types.
#
#AddType application/x-gzip .tgz
#
# AddEncoding allows you to have certain browsers uncompress
# information on the fly. Note: Not all browsers support this.
#
#AddEncoding x-compress .Z
#AddEncoding x-gzip .gz .tgz
#
# If the AddEncoding directives above are commented-out, then you
# probably should define those extensions to indicate media types:
#
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
#
# AddHandler allows you to map certain file extensions to "handlers":
# actions unrelated to filetype. These can be either built into the server
# or added with the Action directive (see below)
#
# To use CGI scripts outside of ScriptAliased directories:
# (You will also need to add "ExecCGI" to the "Options" directive.)
#
#AddHandler cgi-script .cgi
# For type maps (negotiated resources):
#AddHandler type-map var
#
# Filters allow you to process content before it is sent to the client.
#
# To parse .shtml files for server-side includes (SSI):
# (You will also need to add "Includes" to the "Options" directive.)
#
#AddType text/html .shtml
#AddOutputFilter INCLUDES .shtml
</IfModule>
#
# The mod_mime_magic module allows the server to use various hints from the
# contents of the file itself to determine its type. The MIMEMagicFile
# directive tells the module where the hint definitions are located.
#
#MIMEMagicFile conf/magic
#
# Customizable error responses come in three flavors:
# 1) plain text 2) local redirects 3) external redirects
#
# Some examples:
#ErrorDocument 500 "The server made a boo boo."
#ErrorDocument 404 /missing.html
#ErrorDocument 404 "/cgi-bin/missing_handler.pl"
#ErrorDocument 402 http://www.example.com/subscription_info.html
#
#
# MaxRanges: Maximum number of Ranges in a request before
# returning the entire resource, or one of the special
# values 'default', 'none' or 'unlimited'.
# Default setting is to accept 200 Ranges.
#MaxRanges unlimited
#
# EnableMMAP and EnableSendfile: On systems that support it,
# memory-mapping or the sendfile syscall may be used to deliver
# files. This usually improves server performance, but must
# be turned off when serving from networked-mounted
# filesystems or if support for these functions is otherwise
# broken on your system.
# Defaults: EnableMMAP On, EnableSendfile Off
#
#EnableMMAP off
#EnableSendfile on
# Supplemental configuration
#
# The configuration files in the conf/extra/ directory can be
# included to add extra features or to modify the default configuration of
# the server, or you may simply copy their contents here and change as
# necessary.
# Server-pool management (MPM specific)
#Include conf/extra/httpd-mpm.conf
# Multi-language error messages
#Include conf/extra/httpd-multilang-errordoc.conf
# Fancy directory listings
#Include conf/extra/httpd-autoindex.conf
# Language settings
#Include conf/extra/httpd-languages.conf
# User home directories
#Include conf/extra/httpd-userdir.conf
# Real-time info on requests and configuration
#Include conf/extra/httpd-info.conf
# Virtual hosts
#Include conf/extra/httpd-vhosts.conf
# Local access to the Apache HTTP Server Manual
#Include conf/extra/httpd-manual.conf
# Distributed authoring and versioning (WebDAV)
#Include conf/extra/httpd-dav.conf
# Various default settings
#Include conf/extra/httpd-default.conf
# Configure mod_proxy_html to understand HTML4/XHTML1
<IfModule proxy_html_module>
Include conf/extra/proxy-html.conf
</IfModule>
# Secure (SSL/TLS) connections
#Include conf/extra/httpd-ssl.conf
#
# Note: The following must must be present to support
# starting without SSL on platforms with no /dev/random equivalent
# but a statically compiled-in mod_ssl.
#
<IfModule ssl_module>
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
</IfModule>

14
front/index.html Normal file
View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="manifest" href="/manifest.json" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Karusic</title>
<link rel="icon" href="/favicon.ico" />
</head>
<body style="width:100vw;height:100vh;min-width:100%;min-height:100%;">
<div id="root" style="width:100%;height:100%;min-width:100%;min-height:100%;"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

View File

@ -1,31 +0,0 @@
// 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'), reports: [ 'html', 'lcovonly' ],
fixWebpackSourcePaths: true
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
});
};

Some files were not shown because too many files have changed in this diff Show More