Compare commits
247 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 57a08c3246 | |||
| 5a331d9815 | |||
| e9221e2393 | |||
| 7318708bd2 | |||
| 66b20f8256 | |||
| b6e6277074 | |||
| fb128070dc | |||
| d0c19e19df | |||
| c41c3f5abc | |||
| 9b18a9f42d | |||
| a8d93fc2a5 | |||
| 6058169818 | |||
| d336f5d18e | |||
| 45fab20cc4 | |||
| b733e1e344 | |||
| 97042faaa3 | |||
| 8815f657e0 | |||
| ecafb17f05 | |||
| f9b426bb30 | |||
| 02c10b8354 | |||
| 5b69fd1de0 | |||
| 2aaf993f7a | |||
| d5e33381a2 | |||
| d231a7476b | |||
| 369256baf2 | |||
| e697a783ae | |||
| 1930cde695 | |||
| bcbfd34feb | |||
| 2d97e39dbe | |||
| c89623c3a8 | |||
| dc3df79fc1 | |||
| 34038a2ce9 | |||
| d8504ee8f8 | |||
| 6a1c6aac46 | |||
| 72d69f2967 | |||
| 7fd6fd3788 | |||
| 41d3b90fd8 | |||
| c55942c24a | |||
| 21f5911b1c | |||
| 71bbe668f6 | |||
| 4a04ac3b70 | |||
| b26840ffba | |||
| 1199e06bef | |||
| 1b7f6e6f70 | |||
| fe6585d509 | |||
| 093c8756b1 | |||
| 2b8a9c3008 | |||
| 1f10a1d5b5 | |||
| 8a852b7a83 | |||
| 38c1215889 | |||
| 1fc1ab76ec | |||
| 2f0541fe3d | |||
| 5c39b7cfe0 | |||
| db055ef58b | |||
| 420bfaccd9 | |||
| 3d41447581 | |||
| a773022f0d | |||
| afcd52815f | |||
| 59ffeb9363 | |||
| b72157377d | |||
| 0946982ab6 | |||
| 8098aeacd9 | |||
| de94eca0ac | |||
| a7edf934f7 | |||
| 7c0d79612a | |||
| 02f1977ff0 | |||
| 1816302ba1 | |||
| 64ae2d044d | |||
| 00f3606da6 | |||
| f77a6f15c2 | |||
| 0e9a87bfe7 | |||
| 994804b640 | |||
| 9265c0a051 | |||
| 71f9ae9553 | |||
| 19de505ca4 | |||
| 13d51c05d8 | |||
| 0bd80b1878 | |||
| bd565ffd7d | |||
| 60922ea3c7 | |||
| 02ac7e09d3 | |||
| 353d95e377 | |||
| 09409dc698 | |||
| 8f6047bb9f | |||
| 715facf35b | |||
| 5ef85cb484 | |||
| 6874e463fa | |||
| 0844525f8e | |||
| 04fc103016 | |||
| 599bcf96b2 | |||
| 6d104948cc | |||
| 9135a9221f | |||
| c440b08bdf | |||
| a3d781f477 | |||
| dcad69d43c | |||
| 02f46169d9 | |||
| fd95d7e845 | |||
| c5190f7b62 | |||
| b0b930926c | |||
| a90cbb938f | |||
| eb8518afab | |||
| dee92f0e3d | |||
| 773e2ac17e | |||
| ff7e7461e9 | |||
| 50a8082f32 | |||
| 28e76b2374 | |||
| d6c2c863eb | |||
| 4d7c0d6acd | |||
| 24c9c2fe5a | |||
| f96f8270ce | |||
| 3c927f91cf | |||
| d4c4d38aef | |||
| 7042959ee3 | |||
| 15830d7adf | |||
| c7d34ed05f | |||
| 1e56b2885a | |||
| 9bc3370f3b | |||
| 5db10ab1c1 | |||
| d9a413f88d | |||
| c2095f4bcf | |||
| fde28a5880 | |||
| 75c31a7c58 | |||
| a95c745ae2 | |||
| 8083d7fa63 | |||
| ac908e49e6 | |||
| 05857a7d7e | |||
| 28a9a1f670 | |||
| 169ba0d2d1 | |||
| d3c02e164f | |||
| 9b212ccb17 | |||
| f295fcc693 | |||
| 8524ecd6ca | |||
| d1d54c82f9 | |||
| eed5454755 | |||
| 89d70b32d2 | |||
| 5032985787 | |||
| ec5cc7cc0c | |||
| bd5c615017 | |||
| 84203c825c | |||
| d7926a64e2 | |||
| 65a730105d | |||
| 56a9906c58 | |||
| 8f3d1a13de | |||
| 91dc131fba | |||
| d4791a1959 | |||
| 8381a3e4de | |||
| e37ce3c678 | |||
| cc7664519e | |||
| 935b1d01ea | |||
| 947e5d621e | |||
| f5c8910277 | |||
| b9e2e527fd | |||
| 153a7313ef | |||
| 4955a7cc4f | |||
| 78cc13a661 | |||
| e2cf490f9d | |||
| 8c132d12d3 | |||
| df8b7cd007 | |||
| 19c47d3cd2 | |||
| cb48f3017a | |||
| db02993bde | |||
| 3f5aa29a3b | |||
| d6bacc6b4f | |||
| 8254f9387f | |||
| 9aa6593608 | |||
| c76b677f0e | |||
| 829bdeca81 | |||
| 8e18fd9964 | |||
| 134696f73c | |||
| bb18cb53c6 | |||
| 4b3fac59c0 | |||
| 86e46ad205 | |||
| 1f4d4056c7 | |||
| 1760b89e05 | |||
| 3c3f2ef8ad | |||
| 9ef61086df | |||
| a2b4f28c26 | |||
| 2907d40a2e | |||
| 1d648890cc | |||
| 65ad318a5c | |||
| ce02db8f6d | |||
| b487c5f0bc | |||
| e994881ff0 | |||
| e6e3a704bc | |||
| 84aef5d830 | |||
| d35103422b | |||
| 9a6e8c543e | |||
| 81cc70b5e7 | |||
| 6a0e49546c | |||
| c14cfe8a52 | |||
| 6e53f2f1bf | |||
| fa1a03f6e3 | |||
| c537bed4a1 | |||
| 45e46de8f5 | |||
| 58ef4dcdc4 | |||
| f8d5934998 | |||
| 4b241978e0 | |||
| 45a7e60ae4 | |||
| 5a2164b839 | |||
| d2e5586792 | |||
| 96f80e4589 | |||
| 07f2adcc1f | |||
| 0c5a83d3b6 | |||
| 9384011377 | |||
| c0a54291ae | |||
| e408840f6d | |||
| 7dbf3add28 | |||
| 06458cfd10 | |||
| f68217f83a | |||
| 07ab4f83a1 | |||
| b5018dfece | |||
| 7b05343e69 | |||
| 9bd74d036c | |||
| 9ce0e6fcd3 | |||
| 9409638b5c | |||
| dd695a1c2d | |||
| 74f1f6f1c2 | |||
| c0f117a4af | |||
| e0f7c48801 | |||
| e50a9dd95a | |||
| 9dad3e6d37 | |||
| 10d23e456c | |||
| 656aeb17dc | |||
| ce417f8b94 | |||
| 598f074654 | |||
| 3817b1ac5a | |||
| a914282a5d | |||
| 0b0f0b55d0 | |||
| 228f94569b | |||
| 6683ef688e | |||
| e8352dfe3d | |||
| e714c34726 | |||
| 17299a9a94 | |||
| 8bac9db2a9 | |||
| fadd8f468b | |||
| c48d139e6b | |||
| 9a1c690e46 | |||
| 7657691019 | |||
| fb673b100b | |||
| d328d4718f | |||
| 64acb901ff | |||
| 8f4e42c533 | |||
| 5655e46112 | |||
| 37cfacd1e5 | |||
| d05a8a5ce2 | |||
| cf47fb09fe | |||
| 916f4321ea | |||
| 9d7a62c37c |
2
.gitignore
vendored
@@ -7,3 +7,5 @@
|
|||||||
.vscode
|
.vscode
|
||||||
nbactions.xml
|
nbactions.xml
|
||||||
target/
|
target/
|
||||||
|
__pycache__
|
||||||
|
venv
|
||||||
|
|||||||
3
Backend-libXML/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.idea
|
||||||
|
__pycache**
|
||||||
|
venv
|
||||||
8
Backend-libXML/Dockerfile
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
FROM tiangolo/meinheld-gunicorn-flask:python3.9
|
||||||
|
|
||||||
|
COPY ./requirements.txt /app/requirements.txt
|
||||||
|
|
||||||
|
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
|
||||||
|
|
||||||
|
COPY ./main.py /app/
|
||||||
|
COPY ./Parser.py /app/
|
||||||
101
Backend-libXML/Parser.py
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
from lxml import etree
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
|
||||||
|
def formatXML(source: str, prettify: bool) -> str:
|
||||||
|
"""Method used to format XML
|
||||||
|
|
||||||
|
:param source: XML to format
|
||||||
|
:param prettify: sets if XML must be prettified
|
||||||
|
(added indentations etc.) or not
|
||||||
|
:return: formatted XML
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Prolog is removed when XML is parsed
|
||||||
|
# so program has to copy it
|
||||||
|
prolog = ""
|
||||||
|
prolog_start = source.find("<?")
|
||||||
|
|
||||||
|
if prolog_start != -1:
|
||||||
|
prolog_end = source.find("?>") + 2
|
||||||
|
prolog = source[prolog_start:prolog_end]
|
||||||
|
source = source[prolog_end: ]
|
||||||
|
|
||||||
|
byte_input = BytesIO(source.encode("utf-8"))
|
||||||
|
parser = etree.XMLParser(remove_blank_text=True)
|
||||||
|
xml = etree.parse(byte_input, parser=parser)
|
||||||
|
|
||||||
|
if prettify:
|
||||||
|
prolog += "\n"
|
||||||
|
|
||||||
|
return prolog + etree.tostring(xml, pretty_print=prettify).decode()
|
||||||
|
|
||||||
|
|
||||||
|
def xpath(source: str, xpath: str) -> str:
|
||||||
|
"""
|
||||||
|
Method used to get nodes from XML string using XPath
|
||||||
|
|
||||||
|
:param source: XML string used for selection
|
||||||
|
:param xpath: XPath query used for selection
|
||||||
|
:return: Nodes selected using XPath
|
||||||
|
"""
|
||||||
|
|
||||||
|
byte_input = BytesIO(source.encode("utf-8"))
|
||||||
|
root = etree.parse(byte_input).getroot()
|
||||||
|
nsmap = root.nsmap
|
||||||
|
|
||||||
|
# LXML doesn't accept empty (None) namespace prefix,
|
||||||
|
# so it need to be deleted if exists
|
||||||
|
if None in nsmap:
|
||||||
|
nsmap.pop(None)
|
||||||
|
|
||||||
|
result = root.xpath(xpath, namespaces=nsmap)
|
||||||
|
|
||||||
|
# root.xpath can return 4 types: float, string, bool and list.
|
||||||
|
# List is the only one that can't be simply converted to str
|
||||||
|
if type(result) is not list:
|
||||||
|
return str(result), type(result).__name__
|
||||||
|
else:
|
||||||
|
result_string = ""
|
||||||
|
for e in result:
|
||||||
|
result_string += etree.tostring(e, pretty_print=True).decode() + "\n"
|
||||||
|
return result_string, "node"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def xsd(source: str, xsd: str) -> bool:
|
||||||
|
"""
|
||||||
|
Method used to validate XML string against XSD schema
|
||||||
|
:param source: XML string used for validation
|
||||||
|
:param xsd: XSD schema to validate XML against
|
||||||
|
:return: Message saying, if the validation was successful or not
|
||||||
|
"""
|
||||||
|
|
||||||
|
schema_input = BytesIO(xsd.encode("utf-8"))
|
||||||
|
xml_schema = etree.XMLSchema(etree.parse(schema_input).getroot())
|
||||||
|
|
||||||
|
document_input = BytesIO(source.encode("utf-8"))
|
||||||
|
xml = etree.parse(document_input).getroot()
|
||||||
|
|
||||||
|
if xml_schema.validate(xml):
|
||||||
|
return "XML is valid."
|
||||||
|
else:
|
||||||
|
return "XML is NOT valid."
|
||||||
|
|
||||||
|
|
||||||
|
def xslt(source: str, xslt: str) -> str:
|
||||||
|
"""
|
||||||
|
Method used to transform XML string using XSLT
|
||||||
|
|
||||||
|
:param source: XML string to transform
|
||||||
|
:param xslt: XSLT string used to transform XML
|
||||||
|
:return: Result of transformation
|
||||||
|
"""
|
||||||
|
xslt_input = BytesIO(xslt.encode("utf-8"))
|
||||||
|
xslt_transform = etree.XSLT(etree.parse(xslt_input))
|
||||||
|
|
||||||
|
document_input = BytesIO(source.encode("utf-8"))
|
||||||
|
xml = etree.parse(document_input).getroot()
|
||||||
|
|
||||||
|
transformed = str(xslt_transform(xml))
|
||||||
|
return formatXML(transformed, True)
|
||||||
83
Backend-libXML/main.py
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
from flask import Flask
|
||||||
|
from flask_cors import CORS
|
||||||
|
from flask import request
|
||||||
|
from lxml import etree
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import Parser
|
||||||
|
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
CORS(app)
|
||||||
|
# cors = CORS(app, resource={
|
||||||
|
# r"/*":{
|
||||||
|
# "origins":"*"
|
||||||
|
# }
|
||||||
|
# })
|
||||||
|
|
||||||
|
def process_xml(request: request, type: str) -> str:
|
||||||
|
"""Function to process
|
||||||
|
|
||||||
|
:param request: Received request
|
||||||
|
:param type: Type of needed processing: xsd, xslt or xpath
|
||||||
|
:raises ValueError: is raised when type is different than those provided above
|
||||||
|
:return: response JSON converted to string and response code
|
||||||
|
"""
|
||||||
|
start = time.time_ns()
|
||||||
|
code = 200
|
||||||
|
response_json = dict()
|
||||||
|
try:
|
||||||
|
request_data = json.loads(request.get_data(as_text=True))
|
||||||
|
data = request_data['data']
|
||||||
|
process = request_data['process']
|
||||||
|
if (type == "xsd"):
|
||||||
|
response_json['result'] = Parser.xsd(data, process)
|
||||||
|
elif (type == "xslt"):
|
||||||
|
response_json['result'] = Parser.xslt(data, process)
|
||||||
|
elif (type == "xpath"):
|
||||||
|
response_json['result'], response_json['type'] = Parser.xpath(data, process)
|
||||||
|
elif (type == "prettify"):
|
||||||
|
response_json['result'] = Parser.formatXML(data, True)
|
||||||
|
elif (type == "minimize"):
|
||||||
|
response_json['result'] = Parser.formatXML(data, False)
|
||||||
|
else:
|
||||||
|
raise ValueError("Valid operation types are: xsd, xslt, xpath")
|
||||||
|
|
||||||
|
response_json['status'] = "OK"
|
||||||
|
except KeyError as e:
|
||||||
|
response_json['result'] = "Missing key: " + str(e)
|
||||||
|
response_json['status'] = "ERR"
|
||||||
|
code = 400
|
||||||
|
except Exception as e:
|
||||||
|
response_json['result'] = str(e)
|
||||||
|
response_json['status'] = "ERR"
|
||||||
|
code = 400
|
||||||
|
finally:
|
||||||
|
exec_time = (time.time_ns() - start) / 10**6
|
||||||
|
response_json['time'] = f"{exec_time:.03f}"
|
||||||
|
response_json['processor'] = "libxml2 over lxml"
|
||||||
|
return json.dumps(response_json), code
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/xpath", methods=["POST"])
|
||||||
|
def xpath():
|
||||||
|
return process_xml(request, "xpath")
|
||||||
|
|
||||||
|
@app.route("/xsd", methods=["POST"])
|
||||||
|
def xsd():
|
||||||
|
return process_xml(request, "xsd")
|
||||||
|
|
||||||
|
@app.route("/xslt", methods=["POST"])
|
||||||
|
def xslt():
|
||||||
|
return process_xml(request, "xslt")
|
||||||
|
|
||||||
|
@app.route("/prettify", methods=["POST"])
|
||||||
|
def prettify():
|
||||||
|
return process_xml(request, "prettify")
|
||||||
|
|
||||||
|
@app.route("/minimize", methods=["POST"])
|
||||||
|
def minimize():
|
||||||
|
return process_xml(request, "minimize")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run()
|
||||||
3
Backend-libXML/requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
lxml==4.9.2
|
||||||
|
flask==2.3.2
|
||||||
|
flask_cors==3.0.10
|
||||||
19
Backend/mocked-services/Dockerfile
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
FROM maven:3.6.3-jdk-14 as builder
|
||||||
|
WORKDIR application
|
||||||
|
COPY ./ ./
|
||||||
|
RUN mvn clean install
|
||||||
|
|
||||||
|
FROM openjdk:14 as layerBuilder
|
||||||
|
WORKDIR application
|
||||||
|
ARG JAR_FILE=application/target/*.jar
|
||||||
|
COPY --from=builder ${JAR_FILE} application.jar
|
||||||
|
RUN java -Djarmode=layertools -jar application.jar extract
|
||||||
|
|
||||||
|
FROM openjdk:14
|
||||||
|
WORKDIR application
|
||||||
|
COPY --from=layerBuilder application/dependencies/ ./
|
||||||
|
COPY --from=layerBuilder application/spring-boot-loader/ ./
|
||||||
|
COPY --from=layerBuilder application/snapshot-dependencies/ ./
|
||||||
|
COPY --from=layerBuilder application/application/ ./
|
||||||
|
|
||||||
|
ENTRYPOINT ["java", "-Djava.security.cgd=file:/dev/./urandom", "-Dspring.profiles.active=DEV", "org.springframework.boot.loader.JarLauncher"]
|
||||||
48
Backend/mocked-services/README.md
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
# R11-MockedServices
|
||||||
|
Mockup service for middleware testing.
|
||||||
|
|
||||||
|
Available scripts:
|
||||||
|
|
||||||
|
### Running the application on a local machine
|
||||||
|
For Intellij:
|
||||||
|
Plugins:
|
||||||
|
settings -> plugins -> install lombok plugin
|
||||||
|
settings -> annotation processors -> enable annotation processing
|
||||||
|
|
||||||
|
A connection to a Redis database is expected to run the application successfully. You need to download and run Redis DB on
|
||||||
|
your local machine with default values localhost 6379.
|
||||||
|
|
||||||
|
You can also run the application via Docker.
|
||||||
|
#### docker-compose up --build -d
|
||||||
|
|
||||||
|
However, you need either to run it with Docker-compose ensuring that all containers are within a network or start application locally.
|
||||||
|
In order to change environment two properties must be changed.
|
||||||
|
|
||||||
|
1) data-access.properties - property redis.host
|
||||||
|
2) logback.xml - configuration/appender/host element value
|
||||||
|
|
||||||
|
If application is to be run locally, both of above should be set to "localhost"
|
||||||
|
If application is to be run in docker environment, both should be set to name of a redis container (by default "redis")
|
||||||
|
|
||||||
|
Docker automaticly translates container name to IP address, considering all containers are within same network.
|
||||||
|
Try to avoid using any symbols in names of containers, because it may cause that URL exception to be thrown. Instead use letters only.
|
||||||
|
|
||||||
|
### Operations on Redis DB
|
||||||
|
|
||||||
|
Use Redis CLI or attach to Redis docker image in order to manually operate on DB.
|
||||||
|
|
||||||
|
#### docker exec -it mockedservices_redis-server redis-cli
|
||||||
|
Attach to redis server image and open a redis client.
|
||||||
|
|
||||||
|
Useful redis-cli commands:
|
||||||
|
###### KEYS *
|
||||||
|
Show all keys in the db.
|
||||||
|
###### TYPE key
|
||||||
|
Show key type.
|
||||||
|
###### LRANGE key start stop
|
||||||
|
Display elements from the list.
|
||||||
|
###### LLEN key
|
||||||
|
Display list length.
|
||||||
|
###### SMEMBERS key
|
||||||
|
Display elements from hashSet.
|
||||||
|
Logs can be found in lists with names logstash_yyyy-mm-dd.
|
||||||
20
Backend/mocked-services/docker-compose.yml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
redis:
|
||||||
|
image: 'redis'
|
||||||
|
restart: "no"
|
||||||
|
klaus:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: klaus
|
||||||
|
restart: "no"
|
||||||
|
ports:
|
||||||
|
- "8097:8097"
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
environment:
|
||||||
|
SPRING_PROFILES_ACTIVE: DEV
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
name: shared_network_mocked_services
|
||||||
105
Backend/mocked-services/pom.xml
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.7.11</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>mocked-services</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<java.version>11</java.version>
|
||||||
|
<jedis.version>3.3.0</jedis.version>
|
||||||
|
<logback-redis-appender.version>1.1.6</logback-redis-appender.version>
|
||||||
|
<assertj.version>3.16.1</assertj.version>
|
||||||
|
<mapstruct.version>1.5.5.Final</mapstruct.version>
|
||||||
|
<docker.image.prefix>Release11</docker.image.prefix>
|
||||||
|
<docker.image.name>${project.artifactId}</docker.image.name>
|
||||||
|
<lombok.version>1.18.26</lombok.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-devtools</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>${lombok.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct</artifactId>
|
||||||
|
<version>${mapstruct.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<layers>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
<includeLayerTools>true</includeLayerTools>
|
||||||
|
</layers>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<annotationProcessorPaths>
|
||||||
|
<path>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct-processor</artifactId>
|
||||||
|
<version>${mapstruct.version}</version>
|
||||||
|
</path>
|
||||||
|
<path>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>${lombok.version}</version>
|
||||||
|
</path>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok-mapstruct-binding</artifactId>
|
||||||
|
<version>0.2.0</version>
|
||||||
|
</dependency>
|
||||||
|
</annotationProcessorPaths>
|
||||||
|
<compilerArgs>
|
||||||
|
<compilerArg>-Amapstruct.defaultComponentModel=spring</compilerArg>
|
||||||
|
</compilerArgs>
|
||||||
|
<source>13</source>
|
||||||
|
<target>13</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.r11.tools;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It's generic Spring context starter. Move along...
|
||||||
|
*
|
||||||
|
* @author Rafał Żukowicz
|
||||||
|
*/
|
||||||
|
@SpringBootApplication
|
||||||
|
public class KlausApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(KlausApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package com.r11.tools.configuration;
|
||||||
|
|
||||||
|
import com.r11.tools.repository.MockedResponseRepository;
|
||||||
|
import com.r11.tools.repository.RequestHistoryRepository;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Based on configuration deletes all outdated messages and history records from database.
|
||||||
|
*
|
||||||
|
* @author Mikołaj Widła
|
||||||
|
*/
|
||||||
|
|
||||||
|
@EnableScheduling
|
||||||
|
@EnableAsync
|
||||||
|
@Configuration
|
||||||
|
public class RetentionConfiguration {
|
||||||
|
|
||||||
|
private final MockedResponseRepository responseRepository;
|
||||||
|
private final RequestHistoryRepository historyRepository;
|
||||||
|
private final RetentionConfigurationProperties retentionProperties;
|
||||||
|
private final Logger log = LogManager.getRootLogger();
|
||||||
|
|
||||||
|
|
||||||
|
public RetentionConfiguration(MockedResponseRepository responseRepository,
|
||||||
|
RequestHistoryRepository historyRepository,
|
||||||
|
RetentionConfigurationProperties retentionProperties){
|
||||||
|
this.historyRepository = historyRepository;
|
||||||
|
this.responseRepository = responseRepository;
|
||||||
|
this.retentionProperties = retentionProperties;
|
||||||
|
}
|
||||||
|
@Scheduled(fixedDelayString = "#{${retention.retention-cooldown} * 60000 }")
|
||||||
|
@Async
|
||||||
|
public void deleteMessagesAndHistoryRecords(){
|
||||||
|
log.info("OUTDATED MESSAGES AND HISTORY RECORDS DELETED!");
|
||||||
|
responseRepository
|
||||||
|
.findAll()
|
||||||
|
.iterator()
|
||||||
|
.forEachRemaining( mockedMessage -> {
|
||||||
|
if (mockedMessage.getCreatedAt().plusMinutes(retentionProperties.getMinutesToDeleteMessage()).isBefore(LocalDateTime.now())){
|
||||||
|
responseRepository.delete(mockedMessage);
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
historyRepository
|
||||||
|
.findAll()
|
||||||
|
.iterator()
|
||||||
|
.forEachRemaining(
|
||||||
|
historyRecord -> {
|
||||||
|
if (historyRecord.getDateTimeStamp().plusMinutes(retentionProperties.getMinutesToDeleteHistoryRecord()).isBefore(LocalDateTime.now())){
|
||||||
|
historyRepository.delete(historyRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.r11.tools.configuration;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import javax.validation.constraints.Positive;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store all properties needed to change a retention in {@link RetentionConfiguration}
|
||||||
|
*
|
||||||
|
* @author Mikołaj Widła
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "retention")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class RetentionConfigurationProperties {
|
||||||
|
@Positive
|
||||||
|
private Integer minutesToDeleteMessage;
|
||||||
|
@Positive
|
||||||
|
private Integer minutesToDeleteHistoryRecord;
|
||||||
|
@Positive
|
||||||
|
private Integer retentionCooldown;
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.r11.tools.configuration;
|
||||||
|
|
||||||
|
import com.r11.tools.interceptor.IncomingMockRequestInterceptor;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for {@link IncomingMockRequestInterceptor}
|
||||||
|
*
|
||||||
|
* @author Mikołaj Widła
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class WebConfig implements WebMvcConfigurer{
|
||||||
|
|
||||||
|
private final IncomingMockRequestInterceptor requestInterceptor;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
|
registry.addInterceptor( requestInterceptor )
|
||||||
|
.addPathPatterns("/api/mock/r/**");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
package com.r11.tools.controller;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.r11.tools.model.MockedMessageDto;
|
||||||
|
import com.r11.tools.service.KlausService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the homepage and provides the api for javascript async requests.
|
||||||
|
* @author Gabriel Modzelewski
|
||||||
|
* @author Mikołaj Widła
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(path = "/api/mock")
|
||||||
|
@AllArgsConstructor
|
||||||
|
@CrossOrigin(origins = "*")
|
||||||
|
public class MockController {
|
||||||
|
private final KlausService klausService;
|
||||||
|
private final Logger log = LogManager.getRootLogger();
|
||||||
|
|
||||||
|
@ExceptionHandler(Exception.class)
|
||||||
|
public void errorHandler(Exception ex){
|
||||||
|
log.error(Arrays.toString(ex.getStackTrace()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates queried message with given set of data
|
||||||
|
* @param body {@link MockedMessageDto} json representation
|
||||||
|
* @return confirmation and 200 OK
|
||||||
|
*/
|
||||||
|
@SneakyThrows
|
||||||
|
@PutMapping
|
||||||
|
public ResponseEntity<String> updateMessage(@RequestBody String body){
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
MockedMessageDto message = mapper.readValue(body, MockedMessageDto.class);
|
||||||
|
return klausService.setMockedResponse(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the full list of messages. It's used by javascript on the client side to initialize homepage
|
||||||
|
* with data from the database.
|
||||||
|
* @param uuidValue the key-uuid of given set of messages
|
||||||
|
* @return responds with 200 OK and {@link MockedMessageDto}
|
||||||
|
*/
|
||||||
|
@GetMapping({"/", "/{uuidValue}"})
|
||||||
|
public MockedMessageDto getMessage(@PathVariable(required = false) String uuidValue){
|
||||||
|
UUID clientUUID;
|
||||||
|
MockedMessageDto message ;
|
||||||
|
if(uuidValue == null || uuidValue.equals("")) clientUUID = UUID.randomUUID();
|
||||||
|
else clientUUID = UUID.fromString(uuidValue);
|
||||||
|
message = klausService
|
||||||
|
.getMockedMessageByClientUUID(clientUUID)
|
||||||
|
.orElse( buildDefaultMessage(clientUUID) );
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs message with default set of data
|
||||||
|
* @param uuid the key-uuid of given set of messages
|
||||||
|
* @return message with default dataset
|
||||||
|
*/
|
||||||
|
private MockedMessageDto buildDefaultMessage(UUID uuid){
|
||||||
|
Map<String, String> headers = new HashMap<>();
|
||||||
|
headers.put("Keep-Alive", "timeout=60");
|
||||||
|
headers.put("Connection", "keep-alive");
|
||||||
|
headers.put("Date", LocalDateTime.now().toString());
|
||||||
|
MockedMessageDto mockedMessageDto = MockedMessageDto.builder()
|
||||||
|
.clientUUID(uuid)
|
||||||
|
.contentType(MediaType.APPLICATION_XML_VALUE)
|
||||||
|
.messageBody("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
|
||||||
|
"<note>\n" +
|
||||||
|
" <to>Tove</to>\n" +
|
||||||
|
" <from>Jani</from>\n" +
|
||||||
|
" <heading>Reminder</heading>\n" +
|
||||||
|
" <body>Don't forget me this weekend!</body>\n" +
|
||||||
|
"</note>")
|
||||||
|
.httpHeaders(headers)
|
||||||
|
.httpStatus(200)
|
||||||
|
.build();
|
||||||
|
klausService.setMockedResponse(mockedMessageDto);
|
||||||
|
return mockedMessageDto;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* It's one of the most important features - the bread and butter of the Mocked Service. It's link that allows
|
||||||
|
* to receive mocked response from the server and use it to mock!
|
||||||
|
* @param clientUUID the key-uuid of given set of messages
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@RequestMapping(value = "/r/{clientUUID}")
|
||||||
|
public ResponseEntity getMockedResponse(
|
||||||
|
@PathVariable UUID clientUUID) {
|
||||||
|
MockedMessageDto mockedMessageDto = klausService.getMockedResponse(clientUUID);
|
||||||
|
HttpHeaders httpHeaders = new HttpHeaders();
|
||||||
|
if (mockedMessageDto.getHttpHeaders() != null) mockedMessageDto.getHttpHeaders().forEach(httpHeaders::set);
|
||||||
|
httpHeaders.add("Content-Type", mockedMessageDto.getContentType());
|
||||||
|
return new ResponseEntity<>(mockedMessageDto.getMessageBody(), httpHeaders,
|
||||||
|
Objects.requireNonNull(HttpStatus.valueOf(mockedMessageDto.getHttpStatus())));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.r11.tools.controller;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.validation.ConstraintViolationException;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.validation.BindException;
|
||||||
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom exception handler for {@link ConstraintViolationException}
|
||||||
|
* @author Rafał Żukowicz
|
||||||
|
*/
|
||||||
|
@ControllerAdvice
|
||||||
|
@CrossOrigin(origins = "*")
|
||||||
|
public class MvcExceptionHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides handling for {@link ConstraintViolationException}
|
||||||
|
* @param e exception argument
|
||||||
|
* @return response with error list and status 400 bad request
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(ConstraintViolationException.class)
|
||||||
|
public ResponseEntity<List> validationErrorHandler(ConstraintViolationException e){
|
||||||
|
List<String> errors = new ArrayList<>(e.getConstraintViolations().size());
|
||||||
|
|
||||||
|
e.getConstraintViolations().forEach(constraintViolation -> {
|
||||||
|
errors.add(constraintViolation.getPropertyPath() + " : " + constraintViolation.getMessage());
|
||||||
|
});
|
||||||
|
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides handling for {@link BindException}
|
||||||
|
* @param ex exception argument
|
||||||
|
* @return response with error list and status 400 bad request
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(BindException.class)
|
||||||
|
public ResponseEntity<List> handleBindException(BindException ex){
|
||||||
|
return new ResponseEntity(ex.getAllErrors(), HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.r11.tools.controller;
|
||||||
|
|
||||||
|
import com.r11.tools.mappers.RequestHistoryMapper;
|
||||||
|
import com.r11.tools.model.RequestHistory;
|
||||||
|
import com.r11.tools.model.RequestHistoryDTO;
|
||||||
|
import com.r11.tools.service.RequestHistoryService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It's the REST api for {@link RequestHistory}
|
||||||
|
* @author Gabriel Modzelewski
|
||||||
|
* @author Mikołaj Widła
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(path = "/api/event")
|
||||||
|
@AllArgsConstructor
|
||||||
|
@CrossOrigin(origins = "*")
|
||||||
|
public class RequestHistoryController {
|
||||||
|
private final RequestHistoryService service;
|
||||||
|
private final RequestHistoryMapper mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of Events.
|
||||||
|
* @param uuid unique id of message list
|
||||||
|
* @return list of {@link RequestHistory}
|
||||||
|
*/
|
||||||
|
@GetMapping(path = "/{uuid}")
|
||||||
|
public ResponseEntity<List<RequestHistoryDTO>> getLastDay(@PathVariable String uuid){
|
||||||
|
List<RequestHistoryDTO> requestHistory = service.getHistoryRecordsByUUID(
|
||||||
|
uuid
|
||||||
|
).stream()
|
||||||
|
.map(mapper::requestHistoryToRequestHistoryDTO)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return ResponseEntity.ok(requestHistory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package com.r11.tools.interceptor;
|
||||||
|
|
||||||
|
import com.r11.tools.model.RequestHistoryDTO;
|
||||||
|
import com.r11.tools.service.RequestHistoryService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.StreamUtils;
|
||||||
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
import org.springframework.web.servlet.HandlerMapping;
|
||||||
|
import org.springframework.web.util.ContentCachingRequestWrapper;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interceptor that gets needed data from HttpRequest, and saves it to history
|
||||||
|
* @author Mikołaj Widła
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class IncomingMockRequestInterceptor implements HandlerInterceptor {
|
||||||
|
|
||||||
|
private final RequestHistoryService historyService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean preHandle(HttpServletRequest httpRequest, HttpServletResponse response, Object handler){
|
||||||
|
Map<String,String> headers = getHeadersFromHttpRequest(httpRequest);
|
||||||
|
Map<String,String> pathVariable = getPathVariablesFromHttpRequest(httpRequest);
|
||||||
|
String requestBody = getRequestBodyFromHttpRequest(httpRequest);
|
||||||
|
|
||||||
|
RequestHistoryDTO historyDTO = RequestHistoryDTO.builder()
|
||||||
|
.httpMethod(HttpMethod.valueOf(httpRequest.getMethod()))
|
||||||
|
.headers( headers )
|
||||||
|
.clientUUID(UUID.fromString(pathVariable.get("clientUUID")))
|
||||||
|
.dateTimeStamp(LocalDateTime.now())
|
||||||
|
.requestBody(requestBody)
|
||||||
|
.build();
|
||||||
|
historyService.saveRequest(historyDTO);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String,String> getHeadersFromHttpRequest( HttpServletRequest httpRequest ){
|
||||||
|
Set<String> headersName = StreamSupport.stream(
|
||||||
|
Spliterators.spliteratorUnknownSize(
|
||||||
|
httpRequest.getHeaderNames().asIterator(),
|
||||||
|
Spliterator.ORDERED
|
||||||
|
), false
|
||||||
|
).collect(Collectors.toSet());
|
||||||
|
|
||||||
|
return headersName.stream()
|
||||||
|
.collect(Collectors.toMap(
|
||||||
|
value -> value,
|
||||||
|
httpRequest::getHeader
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String,String> getPathVariablesFromHttpRequest( HttpServletRequest httpRequest ){
|
||||||
|
return (Map<String, String>) httpRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getRequestBodyFromHttpRequest( HttpServletRequest httpRequest ){
|
||||||
|
HttpServletRequest wrappedRequest = new ContentCachingRequestWrapper(httpRequest);
|
||||||
|
try {
|
||||||
|
return StreamUtils.copyToString(wrappedRequest.getInputStream(), Charset.defaultCharset());
|
||||||
|
} catch (IOException e) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.r11.tools.mappers;
|
||||||
|
|
||||||
|
import com.r11.tools.model.MockedMessage;
|
||||||
|
import com.r11.tools.model.MockedMessageDto;
|
||||||
|
import org.mapstruct.*;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates key value for redis entry
|
||||||
|
* @author Rafał Źukowicz
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface MockedMessageMapper {
|
||||||
|
@Mapping( target = "createdAt" , expression = "java(java.time.LocalDateTime.now())")
|
||||||
|
MockedMessage mockedMessageDtoToMockedMessage(MockedMessageDto mockedMessageDto);
|
||||||
|
MockedMessageDto mockedMessageToMockedMessageDto(MockedMessage mockedMessage);
|
||||||
|
|
||||||
|
default Optional<MockedMessageDto> optionalMockedMessageToOptionalMockedMessageDTO(Optional<MockedMessage> optionalMockedMessage){
|
||||||
|
return optionalMockedMessage.map(this::mockedMessageToMockedMessageDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
default Optional<MockedMessage> optionalMockedMessageDTOToOptionalMockedMessage(Optional<MockedMessageDto> optionalMockedMessageDto){
|
||||||
|
return optionalMockedMessageDto.map(this::mockedMessageDtoToMockedMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.r11.tools.mappers;
|
||||||
|
|
||||||
|
import com.r11.tools.model.RequestHistory;
|
||||||
|
import com.r11.tools.model.RequestHistoryDTO;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map between DTO and Entity
|
||||||
|
*
|
||||||
|
* @author Mikołaj Widła
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface RequestHistoryMapper {
|
||||||
|
|
||||||
|
@Mapping(target = "clientUUID", expression = "java(requestHistoryDTO.getClientUUID().toString())")
|
||||||
|
RequestHistory requestHistoryDTOToRequestHistory(RequestHistoryDTO requestHistoryDTO);
|
||||||
|
@Mapping(target = "clientUUID", expression = "java(java.util.UUID.fromString(requestHistory.getClientUUID()))")
|
||||||
|
RequestHistoryDTO requestHistoryToRequestHistoryDTO(RequestHistory requestHistory);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package com.r11.tools.model;
|
||||||
|
|
||||||
|
import com.r11.tools.model.constraints.HttpCode;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.redis.core.RedisHash;
|
||||||
|
import org.springframework.data.redis.core.index.Indexed;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MockedMessage redis entity pojo
|
||||||
|
* @author Rafał Żukowicz
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ToString
|
||||||
|
@RedisHash("mockedMessage")
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class MockedMessage implements Serializable {
|
||||||
|
@Indexed
|
||||||
|
@Id
|
||||||
|
private UUID clientUUID;
|
||||||
|
private String contentType;
|
||||||
|
private String messageBody;
|
||||||
|
private Map<String, String> httpHeaders;
|
||||||
|
@HttpCode
|
||||||
|
private Integer httpStatus;
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.r11.tools.model;
|
||||||
|
|
||||||
|
import com.r11.tools.model.constraints.HttpCode;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alternative version of {@link MockedMessage} used in http body
|
||||||
|
* @author Rafał Żukowicz
|
||||||
|
* @author Gabriel Modzelewski
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@ToString
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class MockedMessageDto implements Serializable{
|
||||||
|
private UUID clientUUID;
|
||||||
|
private String contentType;
|
||||||
|
private String messageBody;
|
||||||
|
private Map<String, String> httpHeaders;
|
||||||
|
@HttpCode
|
||||||
|
private Integer httpStatus;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.r11.tools.model;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.redis.core.RedisHash;
|
||||||
|
import org.springframework.data.redis.core.index.Indexed;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pojo class for Event entity
|
||||||
|
* @author Rafał Żukowicz
|
||||||
|
* @author Mikołaj Widła
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@RedisHash("mockHistory")
|
||||||
|
public class RequestHistory implements Comparable<RequestHistory>, Serializable {
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-ddTHH:mm:ss")
|
||||||
|
private LocalDateTime dateTimeStamp;
|
||||||
|
@Indexed
|
||||||
|
private String clientUUID;
|
||||||
|
private Map<String,String> headers;
|
||||||
|
private HttpMethod httpMethod;
|
||||||
|
private String requestBody;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(RequestHistory o) {
|
||||||
|
return this.getDateTimeStamp().compareTo(o.getDateTimeStamp()) * -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.r11.tools.model;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pojo for history query request. Contains information necessary to obtain {@link RequestHistory} list
|
||||||
|
* @author Rafał Żukowicz
|
||||||
|
* @author Mikołaj Widła
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class RequestHistoryDTO {
|
||||||
|
|
||||||
|
private UUID clientUUID;
|
||||||
|
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
|
||||||
|
private LocalDateTime dateTimeStamp;
|
||||||
|
private Map<String,String> headers;
|
||||||
|
private HttpMethod httpMethod;
|
||||||
|
private String requestBody;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.r11.tools.model.constraints;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
import javax.validation.Constraint;
|
||||||
|
import javax.validation.Payload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Annotation interface that is used to annotate Integer fields that contain http status values.
|
||||||
|
* It provides validation and throws an error when trying to send response with incorrect status.
|
||||||
|
* @author Rafał Żukowicz
|
||||||
|
*/
|
||||||
|
@Target({ ElementType.FIELD})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Constraint(validatedBy = HttpCodeValidation.class )
|
||||||
|
public @interface HttpCode {
|
||||||
|
String message() default "must be a valid http code";
|
||||||
|
|
||||||
|
Class<?>[] groups() default { };
|
||||||
|
Class<? extends Payload>[] payload() default { };
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package com.r11.tools.model.constraints;
|
||||||
|
|
||||||
|
import com.r11.tools.model.MockedMessage;
|
||||||
|
import com.r11.tools.model.MockedMessageDto;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import javax.validation.ConstraintValidator;
|
||||||
|
import javax.validation.ConstraintValidatorContext;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It's validator class. It checks if status value of {@link MockedMessageDto} is within bonds of http status values map.
|
||||||
|
* @author Rafał Żukowicz
|
||||||
|
*/
|
||||||
|
public class HttpCodeValidation implements ConstraintValidator<HttpCode, Integer> {
|
||||||
|
private Set<Integer> allowedValues;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes {@link #allowedValues} with possible http status values.
|
||||||
|
* @param targetEnum HttpCode context
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void initialize(HttpCode targetEnum) {
|
||||||
|
allowedValues = Stream.of(HttpStatus.values())
|
||||||
|
.map(HttpStatus::value)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param integer value of {@link MockedMessageDto#getHttpStatus()} or {@link MockedMessage#getHttpStatus()}
|
||||||
|
* @param context context for validation
|
||||||
|
* @return true if valid
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isValid(Integer integer, ConstraintValidatorContext context) {
|
||||||
|
return allowedValues.contains(integer);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.r11.tools.repository;
|
||||||
|
|
||||||
|
import com.r11.tools.model.MockedMessage;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring repository that allows to retrieve message list by key-uuid from redis database
|
||||||
|
* @author Rafał Żukowicz
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
@Transactional
|
||||||
|
public interface MockedResponseRepository extends CrudRepository<MockedMessage, UUID> {
|
||||||
|
/**
|
||||||
|
* Finds all messages by their uuid
|
||||||
|
* @param clientUUID the key-uuid of given set of messages
|
||||||
|
* @return Optional of list of {@link com.r11.tools.model.MockedMessage}
|
||||||
|
*/
|
||||||
|
Optional<MockedMessage> findAllByClientUUID(UUID clientUUID);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.r11.tools.repository;
|
||||||
|
|
||||||
|
import com.r11.tools.model.RequestHistory;
|
||||||
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* History Record entity dao interface
|
||||||
|
* @author Rafał Żukowicz
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
@Transactional
|
||||||
|
public interface RequestHistoryRepository extends CrudRepository<RequestHistory,String> {
|
||||||
|
List<RequestHistory> findAllByClientUUID(String clientUUID);
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.r11.tools.service;
|
||||||
|
|
||||||
|
import com.r11.tools.model.MockedMessageDto;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service interface for {@link com.r11.tools.controller.KlausController} and {@link com.r11.tools.controller.MockController}
|
||||||
|
* @author Rafał Żukowicz
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public interface KlausService {
|
||||||
|
Optional<MockedMessageDto> getMockedMessageByClientUUID(UUID clientUUID);
|
||||||
|
MockedMessageDto getMockedResponse(UUID clientUUID);
|
||||||
|
ResponseEntity<String> setMockedResponse(MockedMessageDto mockedMessageDto);
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package com.r11.tools.service;
|
||||||
|
|
||||||
|
import com.r11.tools.mappers.MockedMessageMapper;
|
||||||
|
import com.r11.tools.model.MockedMessage;
|
||||||
|
import com.r11.tools.model.MockedMessageDto;
|
||||||
|
import com.r11.tools.repository.MockedResponseRepository;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for {@link com.r11.tools.controller.MockController} and {@link com.r11.tools.controller.MockController}
|
||||||
|
* Allows for performing CRUD operations on {@link MockedMessageDto}
|
||||||
|
* @author Rafał Żukowicz
|
||||||
|
* @author Gabriel Modzelewski
|
||||||
|
* @author Mikołaj Widła
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class KlausServiceImpl implements KlausService {
|
||||||
|
private final MockedMessageMapper mockedMessageMapper;
|
||||||
|
private final Logger log = LogManager.getRootLogger();
|
||||||
|
private final MockedResponseRepository mockedResponseRepository;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all messages of given key-uuid
|
||||||
|
* @param clientUUID the key-uuid of given set of messages
|
||||||
|
* @return List of {@link MockedMessageDto}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Optional<MockedMessageDto> getMockedMessageByClientUUID(UUID clientUUID){
|
||||||
|
Optional<MockedMessage> mockedMessageOptional = mockedResponseRepository.findAllByClientUUID(clientUUID);
|
||||||
|
log.info("Message for UUID: "+clientUUID+" has been fetched from DB.");
|
||||||
|
return mockedMessageMapper.optionalMockedMessageToOptionalMockedMessageDTO(mockedMessageOptional);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@link MockedMessageDto} of given id and key-uuid. If message doesn't then empty message is returned
|
||||||
|
* @param clientUUID the key-uuid of given set of messages
|
||||||
|
* @return {@link MockedMessageDto} object
|
||||||
|
*/
|
||||||
|
@SneakyThrows
|
||||||
|
@Override
|
||||||
|
public MockedMessageDto getMockedResponse(UUID clientUUID){
|
||||||
|
Optional<MockedMessage> optionalMockedMessage = mockedResponseRepository.findById(clientUUID);
|
||||||
|
MockedMessageDto mockedMessageDto = MockedMessageDto.builder()
|
||||||
|
.clientUUID(clientUUID)
|
||||||
|
.build();
|
||||||
|
if (optionalMockedMessage.isPresent()) {
|
||||||
|
mockedMessageDto = mockedMessageMapper.mockedMessageToMockedMessageDto(optionalMockedMessage.get());
|
||||||
|
//log.info(mockedMessageDto.toString().replaceAll("\"", "\\\\\""));
|
||||||
|
return mockedMessageDto;
|
||||||
|
}
|
||||||
|
//log.info(mockedMessageDto.toString().replaceAll("\"", "\\\\\""));
|
||||||
|
return mockedMessageDto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows to modify mocked message. If message of given id and key-uuid doesn't exist a new entry is created
|
||||||
|
* @param mockedMessageDto message to be saved
|
||||||
|
* @return Confirmation and status 200 OK
|
||||||
|
*/
|
||||||
|
@SneakyThrows
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<String> setMockedResponse(MockedMessageDto mockedMessageDto) {
|
||||||
|
mockedResponseRepository.save(mockedMessageMapper.mockedMessageDtoToMockedMessage(mockedMessageDto));
|
||||||
|
//log.info(mockedMessageDto.toString().replaceAll("\"", "\\\\\""));
|
||||||
|
return new ResponseEntity<>("MockedResponse has been setup successfully!", new HttpHeaders(),
|
||||||
|
HttpStatus.ACCEPTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.r11.tools.service;
|
||||||
|
|
||||||
|
import com.r11.tools.controller.RequestHistoryController;
|
||||||
|
import com.r11.tools.model.RequestHistory;
|
||||||
|
import com.r11.tools.model.RequestHistoryDTO;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring service interface for {@link RequestHistoryController}
|
||||||
|
* @author Rafał Żukowicz
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public interface RequestHistoryService {
|
||||||
|
/**
|
||||||
|
* Searches for {@link RequestHistory} objects between date brackets
|
||||||
|
* @param uuid user uuid
|
||||||
|
* @return list of {@link RequestHistory}
|
||||||
|
*/
|
||||||
|
List<RequestHistory> getHistoryRecordsByUUID(String uuid);
|
||||||
|
void saveRequest(RequestHistoryDTO requestDTO);
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.r11.tools.service;
|
||||||
|
|
||||||
|
import com.r11.tools.controller.RequestHistoryController;
|
||||||
|
import com.r11.tools.mappers.RequestHistoryMapper;
|
||||||
|
import com.r11.tools.model.RequestHistory;
|
||||||
|
import com.r11.tools.model.RequestHistoryDTO;
|
||||||
|
import com.r11.tools.repository.RequestHistoryRepository;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring Service for {@link RequestHistoryController}. Contains logic required for quering
|
||||||
|
* the database for {@link RequestHistory} objects
|
||||||
|
* @author Rafał Żukowicz
|
||||||
|
* @author Mikołaj Widła
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class RequestHistoryServiceImpl implements RequestHistoryService {
|
||||||
|
|
||||||
|
private final RequestHistoryRepository repository;
|
||||||
|
private final RequestHistoryMapper requestMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<RequestHistory> getHistoryRecordsByUUID(String uuid) {
|
||||||
|
List<RequestHistory> history = repository.findAllByClientUUID(uuid);
|
||||||
|
Collections.sort(history);
|
||||||
|
return history;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveRequest(RequestHistoryDTO requestDTO) {
|
||||||
|
repository.save(requestMapper.requestHistoryDTOToRequestHistory(requestDTO));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#environment:
|
||||||
|
server.port = 8097
|
||||||
|
spring.application.name = klaus
|
||||||
|
spring.mvc.view.suffix=.html
|
||||||
|
logging.level.root=INFO
|
||||||
|
logging.level.org.springframework.web=INFO
|
||||||
|
logging.level.com.release11=INFO
|
||||||
|
|
||||||
|
#database:
|
||||||
|
spring.redis.host=redis
|
||||||
|
spring.redis.port=6379
|
||||||
|
|
||||||
|
#retention
|
||||||
|
retention.minutes-to-delete-message=120
|
||||||
|
retention.minutes-to-delete-history-record=1440
|
||||||
|
retention.retention-cooldown=1440
|
||||||
25
Backend/mocked-services/src/main/resources/logback.xml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<include resource="org/springframework/boot/logging/logback/base.xml"/>
|
||||||
|
<property name="HOME_LOG" value="/log/mockServices.log"/>
|
||||||
|
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${HOME_LOG}</file>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>logs/mockServices.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
||||||
|
<maxFileSize>10MB</maxFileSize>
|
||||||
|
<totalSizeCap>20GB</totalSizeCap>
|
||||||
|
<maxHistory>60</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<root level="DEBUG">
|
||||||
|
<appender-ref ref="CONSOLE" />
|
||||||
|
<appender-ref ref="FILE" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
||||||
|
|
||||||
|
|
||||||
25
Backend/pom.xml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.r11.tools</groupId>
|
||||||
|
<artifactId>release11-tools</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<jackson.version>2.14.1</jackson.version>
|
||||||
|
<slf4j.version>2.0.6</slf4j.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
<modules>
|
||||||
|
<module>tools-services</module>
|
||||||
|
<module>mocked-services</module>
|
||||||
|
</modules>
|
||||||
|
</project>
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
# Using maven image, based on java 8
|
# Using maven image, based on java 8
|
||||||
FROM maven:3.6.3-jdk-8 as target
|
FROM maven:3.6.3-jdk-8 as target
|
||||||
WORKDIR /build
|
WORKDIR build
|
||||||
COPY pom.xml .
|
COPY ./ ./
|
||||||
COPY src/ /build/src/
|
|
||||||
RUN mvn -ntp package
|
RUN mvn -ntp package
|
||||||
|
|
||||||
|
|
||||||
# Go to working directory in docker image
|
# Go to working directory in docker image
|
||||||
# WORKDIR /usr/app/
|
# WORKDIR /usr/app/
|
||||||
|
|
||||||
128
Backend/tools-services/pom.xml
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.r11.tools</groupId>
|
||||||
|
<artifactId>tools-services</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<jackson.version>2.14.1</jackson.version>
|
||||||
|
<slf4j.version>2.0.6</slf4j.version>
|
||||||
|
<log4j.version>2.19.0</log4j.version>
|
||||||
|
<gson.version>2.10.1</gson.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.1</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.8</source>
|
||||||
|
<target>1.8</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<version>3.3.0</version>
|
||||||
|
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<addClasspath>true</addClasspath>
|
||||||
|
<classpathPrefix>lib/</classpathPrefix>
|
||||||
|
<mainClass>com.r11.tools.SparkInitializer</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
<descriptorRefs>
|
||||||
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
|
</descriptorRefs>
|
||||||
|
</configuration>
|
||||||
|
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>make-assembly</id>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- Spark -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sparkjava</groupId>
|
||||||
|
<artifactId>spark-core</artifactId>
|
||||||
|
<version>2.9.4</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- JSON -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
<version>${gson.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- XSLT -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.sf.saxon</groupId>
|
||||||
|
<artifactId>Saxon-HE</artifactId>
|
||||||
|
<version>11.4</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>xalan</groupId>
|
||||||
|
<artifactId>xalan</artifactId>
|
||||||
|
<version>2.7.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Logging -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
<version>${slf4j.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>jcl-over-slf4j</artifactId>
|
||||||
|
<version>${slf4j.version}</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<version>${slf4j.version}</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-log4j12</artifactId>
|
||||||
|
<version>${slf4j.version}</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-core</artifactId>
|
||||||
|
<version>${log4j.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-api</artifactId>
|
||||||
|
<version>${log4j.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package com.r11.tools;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.r11.tools.controller.JsonController;
|
||||||
|
import com.r11.tools.controller.ProcessorInfoController;
|
||||||
|
import com.r11.tools.controller.XPathController;
|
||||||
|
import com.r11.tools.controller.XsdController;
|
||||||
|
import com.r11.tools.controller.XsltController;
|
||||||
|
import com.r11.tools.controller.internal.RestControllerRegistry;
|
||||||
|
import com.r11.tools.xml.Saxon;
|
||||||
|
import com.r11.tools.xml.Xalan;
|
||||||
|
import com.r11.tools.xml.XmlEngine;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import spark.Spark;
|
||||||
|
|
||||||
|
public class SparkApplication {
|
||||||
|
|
||||||
|
public static void run() {
|
||||||
|
// TODO: read port from config
|
||||||
|
Spark.port(8081);
|
||||||
|
|
||||||
|
Spark.after((request, response) -> {
|
||||||
|
response.header("Access-Control-Allow-Origin", "*");
|
||||||
|
response.header("access-control-allow-headers", "*");
|
||||||
|
response.header("access-control-expose-headers", "*");
|
||||||
|
response.header("Access-Control-Allow-Methods", "POST");
|
||||||
|
});
|
||||||
|
|
||||||
|
Logger logger = LogManager.getLogger(SparkApplication.class);
|
||||||
|
|
||||||
|
Gson gson = new GsonBuilder()
|
||||||
|
.disableHtmlEscaping()
|
||||||
|
.setPrettyPrinting()
|
||||||
|
.create();
|
||||||
|
|
||||||
|
Gson jsongson = new GsonBuilder()
|
||||||
|
.disableHtmlEscaping()
|
||||||
|
.create();
|
||||||
|
XmlEngine saxon = new Saxon();
|
||||||
|
XmlEngine xalan = new Xalan();
|
||||||
|
|
||||||
|
|
||||||
|
RestControllerRegistry registry = new RestControllerRegistry();
|
||||||
|
registry.registerController(new ProcessorInfoController(logger, saxon, xalan));
|
||||||
|
registry.registerController(new XsdController(gson, logger, xalan));
|
||||||
|
registry.registerController(new XPathController(gson, logger, saxon, xalan));
|
||||||
|
registry.registerController(new XsltController(gson, logger, saxon, xalan));
|
||||||
|
registry.registerController(new JsonController(gson, jsongson, logger));
|
||||||
|
|
||||||
|
registry.register();
|
||||||
|
|
||||||
|
logger.info("Server is online at port: " + Spark.port());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.r11.tools;
|
||||||
|
|
||||||
|
public class SparkInitializer {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SparkApplication.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package com.r11.tools.controller;
|
||||||
|
|
||||||
|
import com.google.gson.*;
|
||||||
|
//import com.google.gson.GsonBuilder;
|
||||||
|
import com.r11.tools.controller.internal.GlobalControllerManifest;
|
||||||
|
import com.r11.tools.controller.internal.HandlerType;
|
||||||
|
import com.r11.tools.controller.internal.RestController;
|
||||||
|
import com.r11.tools.controller.internal.ScopedControllerManifest;
|
||||||
|
import spark.Request;
|
||||||
|
import spark.Response;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@GlobalControllerManifest(path = "/json")
|
||||||
|
public class JsonController implements RestController {
|
||||||
|
|
||||||
|
private final Logger logger;
|
||||||
|
|
||||||
|
private final Gson prettyGson;
|
||||||
|
|
||||||
|
private final Gson gson;
|
||||||
|
|
||||||
|
public JsonController(Gson prettyGson, Gson jsongson,Logger logger) {
|
||||||
|
this.logger = logger;
|
||||||
|
this.prettyGson = prettyGson;
|
||||||
|
this.gson = jsongson;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ScopedControllerManifest(method = HandlerType.POST, path = "/formatting")
|
||||||
|
public void formatting(Request request, Response response) {
|
||||||
|
long startProcess = System.currentTimeMillis();
|
||||||
|
JsonObject responseJson = new JsonObject();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Object requestJson = this.gson.fromJson(request.body(), Object.class);
|
||||||
|
|
||||||
|
responseJson.addProperty("data", this.prettyGson.toJson(requestJson));
|
||||||
|
responseJson.addProperty("time", System.currentTimeMillis() - startProcess);
|
||||||
|
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
this.logger.error("Error on formatting Json " + e);
|
||||||
|
Throwable cause = e.getCause();
|
||||||
|
|
||||||
|
response.status(400);
|
||||||
|
|
||||||
|
responseJson.addProperty("data", cause == null ? e.getMessage() : cause.getMessage());
|
||||||
|
responseJson.addProperty("time", System.currentTimeMillis() - startProcess);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
this.logger.info("Json processed in " + responseJson.get("time").toString() + " ms.");
|
||||||
|
response.body(this.prettyGson.toJson(responseJson));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ScopedControllerManifest(method = HandlerType.POST, path = "/minimize")
|
||||||
|
public void minimize(Request request, Response response) {
|
||||||
|
long startProcess = System.currentTimeMillis();
|
||||||
|
JsonObject responseJson = new JsonObject();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Object requestJson = this.prettyGson.fromJson(request.body(), Object.class);
|
||||||
|
|
||||||
|
response.status(200);
|
||||||
|
|
||||||
|
responseJson.addProperty("data", this.gson.toJson(requestJson));
|
||||||
|
responseJson.addProperty("time", System.currentTimeMillis() - startProcess);
|
||||||
|
|
||||||
|
response.body(this.gson.toJson(responseJson));
|
||||||
|
} catch (Exception e) {
|
||||||
|
this.logger.error("Error on minimizeing Json " + e);
|
||||||
|
Throwable cause = e.getCause();
|
||||||
|
|
||||||
|
response.status(400);
|
||||||
|
|
||||||
|
responseJson.addProperty("data", cause == null ? e.getMessage() : cause.getMessage());
|
||||||
|
responseJson.addProperty("time", System.currentTimeMillis() - startProcess);
|
||||||
|
|
||||||
|
response.body(this.prettyGson.toJson(responseJson));
|
||||||
|
}
|
||||||
|
this.logger.info("Json processed in " + responseJson.get("time").toString() + " ms.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package com.r11.tools.controller;
|
||||||
|
|
||||||
|
import com.r11.tools.controller.internal.GlobalControllerManifest;
|
||||||
|
import com.r11.tools.controller.internal.HandlerType;
|
||||||
|
import com.r11.tools.controller.internal.RestController;
|
||||||
|
import com.r11.tools.controller.internal.ScopedControllerManifest;
|
||||||
|
import com.r11.tools.xml.Saxon;
|
||||||
|
import com.r11.tools.xml.XmlEngine;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import spark.Request;
|
||||||
|
import spark.Response;
|
||||||
|
|
||||||
|
@GlobalControllerManifest
|
||||||
|
public class ProcessorInfoController implements RestController {
|
||||||
|
|
||||||
|
private final Logger logger;
|
||||||
|
private final XmlEngine saxon;
|
||||||
|
private final XmlEngine xalan;
|
||||||
|
|
||||||
|
public ProcessorInfoController(Logger logger, XmlEngine saxon, XmlEngine xalan) {
|
||||||
|
this.logger = logger;
|
||||||
|
this.saxon = saxon;
|
||||||
|
this.xalan = xalan;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler that returns processor version
|
||||||
|
*/
|
||||||
|
@ScopedControllerManifest(method = HandlerType.GET, path = "/procinfo")
|
||||||
|
public void processorInfo(Request request, Response response) {
|
||||||
|
try {
|
||||||
|
response.header("processor", "Saxon " + saxon.getVersion() + " over s9api");
|
||||||
|
response.body(saxon.getVersion());
|
||||||
|
} catch (Exception ex) {
|
||||||
|
this.logger.error("Error on retrieving engine version. " + ex);
|
||||||
|
response.body(ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
package com.r11.tools.controller;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.r11.tools.controller.internal.*;
|
||||||
|
import com.r11.tools.xml.XmlEngine;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import spark.Request;
|
||||||
|
import spark.Response;
|
||||||
|
|
||||||
|
@GlobalControllerManifest
|
||||||
|
public class XPathController implements RestController {
|
||||||
|
|
||||||
|
private final Gson gson;
|
||||||
|
private final Logger logger;
|
||||||
|
|
||||||
|
private final XmlEngine saxon;
|
||||||
|
private final XmlEngine xalan;
|
||||||
|
|
||||||
|
public XPathController(Gson gson, Logger logger, XmlEngine saxon, XmlEngine xalan) {
|
||||||
|
this.gson = gson;
|
||||||
|
this.logger = logger;
|
||||||
|
this.saxon = saxon;
|
||||||
|
this.xalan = xalan;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ScopedControllerManifest(method = HandlerType.POST, path = "/xpath")
|
||||||
|
public void transform(Request request, Response response) {
|
||||||
|
String body = request.body();
|
||||||
|
|
||||||
|
JsonObject requestJson;
|
||||||
|
try {
|
||||||
|
requestJson = this.gson.fromJson(body, JsonObject.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
JsonObject responseJson = new JsonObject();
|
||||||
|
responseJson.addProperty("result", e.getMessage());
|
||||||
|
responseJson.addProperty("processor", "N/A");
|
||||||
|
responseJson.addProperty("status", "ERR");
|
||||||
|
responseJson.addProperty("time", "N/A");
|
||||||
|
|
||||||
|
response.status(400);
|
||||||
|
response.body(this.gson.toJson(responseJson));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String data = requestJson.get("data").getAsString();
|
||||||
|
String query = requestJson.get("process").getAsString();
|
||||||
|
String processor = requestJson.get("processor").getAsString();
|
||||||
|
String version = requestJson.get("version").getAsString();
|
||||||
|
|
||||||
|
if (processor == null) {
|
||||||
|
response.body("saxon, xalan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject responseJson = new JsonObject();
|
||||||
|
switch (processor) {
|
||||||
|
case "saxon":
|
||||||
|
processWithSaxon(response, data, query, version, responseJson);
|
||||||
|
break;
|
||||||
|
case "xalan":
|
||||||
|
processWithXalan(response, data, query, responseJson);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
response.body("saxon, xalan");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processWithXalan(Response response, String data, String query, JsonObject responseJson) {
|
||||||
|
long timeStart;
|
||||||
|
long duration;
|
||||||
|
response.header("processor", xalan.getVersion());
|
||||||
|
timeStart = System.currentTimeMillis();
|
||||||
|
|
||||||
|
try {
|
||||||
|
XPathQueryResult xPathQueryResult = xalan.processXPath(data, query, "");
|
||||||
|
|
||||||
|
response.status(200);
|
||||||
|
|
||||||
|
responseJson.addProperty("result", xPathQueryResult.getData().trim());
|
||||||
|
responseJson.addProperty("status", "OK");
|
||||||
|
responseJson.addProperty("type", xPathQueryResult.getType());
|
||||||
|
} catch (Exception ex) {
|
||||||
|
this.logger.error("Error on processing XPath using Xalan. " + ex);
|
||||||
|
|
||||||
|
response.status(400);
|
||||||
|
|
||||||
|
responseJson.addProperty("result", ex.getMessage());
|
||||||
|
responseJson.addProperty("status", "ERR");
|
||||||
|
}
|
||||||
|
|
||||||
|
duration = System.currentTimeMillis() - timeStart;
|
||||||
|
this.logger.info("Request (XPath, Xalan) processed in " + duration + " ms.");
|
||||||
|
|
||||||
|
responseJson.addProperty("processor", xalan.getVersion());
|
||||||
|
responseJson.addProperty("time", duration);
|
||||||
|
|
||||||
|
response.body(this.gson.toJson(responseJson));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processWithSaxon(Response response, String data, String query, String version, JsonObject responseJson) {
|
||||||
|
long timeStart;
|
||||||
|
String tmp;
|
||||||
|
long duration;
|
||||||
|
response.header("processor", "Saxon " + saxon.getVersion() + " " + version + " over s9api");
|
||||||
|
timeStart = System.currentTimeMillis();
|
||||||
|
|
||||||
|
try {
|
||||||
|
tmp = saxon.processXPath(data, query, version).getData().trim();
|
||||||
|
|
||||||
|
response.status(200);
|
||||||
|
|
||||||
|
responseJson.addProperty("result", tmp);
|
||||||
|
responseJson.addProperty("status", "OK");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
this.logger.error("Error on processing XPath using Saxon. " + ex);
|
||||||
|
|
||||||
|
response.status(400);
|
||||||
|
|
||||||
|
responseJson.addProperty("result", ex.getMessage());
|
||||||
|
responseJson.addProperty("status", "ERR");
|
||||||
|
}
|
||||||
|
|
||||||
|
duration = System.currentTimeMillis() - timeStart;
|
||||||
|
this.logger.info("Request (XPath, Saxon) processed in " + duration + " ms.");
|
||||||
|
|
||||||
|
responseJson.addProperty("processor", "Saxon " + saxon.getVersion() + " " + version + " over s9api");
|
||||||
|
responseJson.addProperty("time", duration);
|
||||||
|
|
||||||
|
response.body(this.gson.toJson(responseJson));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package com.r11.tools.controller;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.r11.tools.controller.internal.GlobalControllerManifest;
|
||||||
|
import com.r11.tools.controller.internal.HandlerType;
|
||||||
|
import com.r11.tools.controller.internal.RestController;
|
||||||
|
import com.r11.tools.controller.internal.ScopedControllerManifest;
|
||||||
|
import com.r11.tools.xml.Xalan;
|
||||||
|
import com.r11.tools.xml.XmlEngine;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import spark.Request;
|
||||||
|
import spark.Response;
|
||||||
|
|
||||||
|
@GlobalControllerManifest
|
||||||
|
public class XsdController implements RestController {
|
||||||
|
|
||||||
|
private final Gson gson;
|
||||||
|
private final Logger logger;
|
||||||
|
|
||||||
|
private final XmlEngine xalan;
|
||||||
|
|
||||||
|
public XsdController(Gson gson, Logger logger, XmlEngine xalan) {
|
||||||
|
this.gson = gson;
|
||||||
|
this.logger = logger;
|
||||||
|
this.xalan = xalan;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ScopedControllerManifest(method = HandlerType.POST, path = "/xsd")
|
||||||
|
public Response transform(Request request, Response response) {
|
||||||
|
String body = request.body();
|
||||||
|
|
||||||
|
JsonObject requestJson;
|
||||||
|
try {
|
||||||
|
requestJson = this.gson.fromJson(body, JsonObject.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
JsonObject responseJson = new JsonObject();
|
||||||
|
responseJson.addProperty("result", e.getMessage());
|
||||||
|
responseJson.addProperty("processor", "N/A");
|
||||||
|
responseJson.addProperty("status", "ERR");
|
||||||
|
responseJson.addProperty("time", "N/A");
|
||||||
|
|
||||||
|
response.status(400);
|
||||||
|
response.body(this.gson.toJson(responseJson));
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
String data = requestJson.get("data").getAsString();
|
||||||
|
String xsd = requestJson.get("process").getAsString();
|
||||||
|
|
||||||
|
response.header("processor", xalan.getVersion());
|
||||||
|
|
||||||
|
long timeStart = System.currentTimeMillis();
|
||||||
|
String tmp;
|
||||||
|
|
||||||
|
JsonObject responseJson = new JsonObject();
|
||||||
|
try {
|
||||||
|
tmp = xalan.validate(data, xsd).trim();
|
||||||
|
|
||||||
|
response.status(200);
|
||||||
|
|
||||||
|
responseJson.addProperty("result", tmp);
|
||||||
|
responseJson.addProperty("status", "OK");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
this.logger.error("Error on validation against XSD using Xalan. " + ex);
|
||||||
|
|
||||||
|
response.status(400);
|
||||||
|
|
||||||
|
responseJson.addProperty("result", ex.getMessage());
|
||||||
|
responseJson.addProperty("status", "ERR");
|
||||||
|
}
|
||||||
|
|
||||||
|
long duration = System.currentTimeMillis() - timeStart;
|
||||||
|
this.logger.info("Request (XSD, Xalan) processed in " + duration + " ms.");
|
||||||
|
|
||||||
|
responseJson.addProperty("processor", xalan.getVersion());
|
||||||
|
responseJson.addProperty("time", duration);
|
||||||
|
|
||||||
|
response.body(this.gson.toJson(responseJson));
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
package com.r11.tools.controller;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.r11.tools.controller.internal.GlobalControllerManifest;
|
||||||
|
import com.r11.tools.controller.internal.HandlerType;
|
||||||
|
import com.r11.tools.controller.internal.RestController;
|
||||||
|
import com.r11.tools.controller.internal.ScopedControllerManifest;
|
||||||
|
import com.r11.tools.xml.Saxon;
|
||||||
|
import com.r11.tools.xml.Xalan;
|
||||||
|
import com.r11.tools.xml.XmlEngine;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import spark.Request;
|
||||||
|
import spark.Response;
|
||||||
|
|
||||||
|
@GlobalControllerManifest
|
||||||
|
public class XsltController implements RestController {
|
||||||
|
|
||||||
|
private final Gson gson;
|
||||||
|
private final Logger logger;
|
||||||
|
|
||||||
|
private final XmlEngine saxon;
|
||||||
|
private final XmlEngine xalan;
|
||||||
|
|
||||||
|
public XsltController(Gson gson, Logger logger, XmlEngine saxon, XmlEngine xalan) {
|
||||||
|
this.gson = gson;
|
||||||
|
this.logger = logger;
|
||||||
|
this.saxon = saxon;
|
||||||
|
this.xalan = xalan;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ScopedControllerManifest(method = HandlerType.POST, path = "/xslt")
|
||||||
|
public void transform(Request request, Response response) {
|
||||||
|
String body = request.body();
|
||||||
|
|
||||||
|
JsonObject requestJson;
|
||||||
|
try {
|
||||||
|
requestJson = this.gson.fromJson(body, JsonObject.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
JsonObject responseJson = new JsonObject();
|
||||||
|
responseJson.addProperty("result", e.getMessage());
|
||||||
|
responseJson.addProperty("processor", "N/A");
|
||||||
|
responseJson.addProperty("status", "ERR");
|
||||||
|
responseJson.addProperty("time", "N/A");
|
||||||
|
|
||||||
|
response.status(400);
|
||||||
|
response.body(this.gson.toJson(responseJson));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String data = requestJson.get("data").getAsString();
|
||||||
|
String query = requestJson.get("process").getAsString();
|
||||||
|
String processor = requestJson.get("processor").getAsString();
|
||||||
|
String version = requestJson.get("version").getAsString();
|
||||||
|
|
||||||
|
if (processor == null) {
|
||||||
|
response.body("saxon, xalan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
JsonObject responseJson = new JsonObject();
|
||||||
|
switch (processor) {
|
||||||
|
case "saxon":
|
||||||
|
processWithSaxon(response, data, query, version, responseJson);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case "xalan":
|
||||||
|
processWithXalan(response, data, query, responseJson);
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
response.body("saxon, xalan");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processWithXalan(Response response, String data, String query, JsonObject responseJson) {
|
||||||
|
long duration;
|
||||||
|
long timeStart;
|
||||||
|
String tmp;
|
||||||
|
timeStart = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
|
tmp = xalan.processXSLT(data, query);
|
||||||
|
|
||||||
|
response.status(200);
|
||||||
|
|
||||||
|
responseJson.addProperty("result", tmp);
|
||||||
|
responseJson.addProperty("status", "OK");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
this.logger.error("Error on processing XSLT using Xalan. " + ex);
|
||||||
|
|
||||||
|
response.status(400);
|
||||||
|
|
||||||
|
responseJson.addProperty("result", ex.getMessage());
|
||||||
|
responseJson.addProperty("status", "ERR");
|
||||||
|
}
|
||||||
|
|
||||||
|
duration = System.currentTimeMillis() - timeStart;
|
||||||
|
this.logger.info("Request (XSLT, Xalan) processed in " + duration + " ms.");
|
||||||
|
|
||||||
|
responseJson.addProperty("processor", xalan.getVersion());
|
||||||
|
responseJson.addProperty("time", duration);
|
||||||
|
|
||||||
|
response.body(this.gson.toJson(responseJson));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processWithSaxon(Response response, String data, String query, String version, JsonObject responseJson) {
|
||||||
|
long duration;
|
||||||
|
String tmp;
|
||||||
|
long timeStart;
|
||||||
|
timeStart = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
|
tmp = saxon.processXSLT(data, query);
|
||||||
|
|
||||||
|
response.status(200);
|
||||||
|
|
||||||
|
responseJson.addProperty("result", tmp);
|
||||||
|
responseJson.addProperty("status", "OK");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
this.logger.error("Error on processing XSLT using Saxon. " + ex);
|
||||||
|
|
||||||
|
response.status(400);
|
||||||
|
|
||||||
|
responseJson.addProperty("result", ex.getMessage());
|
||||||
|
responseJson.addProperty("status", "ERR");
|
||||||
|
}
|
||||||
|
|
||||||
|
duration = System.currentTimeMillis() - timeStart;
|
||||||
|
this.logger.info("Request (XSLT, Saxon) processed in " + duration + " ms.");
|
||||||
|
|
||||||
|
responseJson.addProperty("processor", "Saxon " + saxon.getVersion() + " " + version);
|
||||||
|
responseJson.addProperty("time", duration);
|
||||||
|
|
||||||
|
response.body(this.gson.toJson(responseJson));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.r11.tools.controller.internal;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
public @interface GlobalControllerManifest {
|
||||||
|
|
||||||
|
String path() default "";
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.r11.tools.controller.internal;
|
||||||
|
|
||||||
|
public enum HandlerType {
|
||||||
|
|
||||||
|
GET, POST, PUT, DELETE
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.r11.tools.controller.internal;
|
||||||
|
|
||||||
|
public interface RestController {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package com.r11.tools.controller.internal;
|
||||||
|
|
||||||
|
import com.r11.tools.controller.internal.path.PathBuilder;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import spark.Spark;
|
||||||
|
|
||||||
|
public class RestControllerRegistry {
|
||||||
|
|
||||||
|
private final Set<RestController> registeredControllers;
|
||||||
|
|
||||||
|
public RestControllerRegistry() {
|
||||||
|
this.registeredControllers = new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerController(RestController restController) {
|
||||||
|
this.registeredControllers.add(restController);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void register() {
|
||||||
|
this.registeredControllers.forEach(controller -> {
|
||||||
|
if (controller.getClass().isAnnotationPresent(GlobalControllerManifest.class)) {
|
||||||
|
for (Method method : controller.getClass().getMethods()) {
|
||||||
|
this.registerAssignableHandlers(controller.getClass(), controller, method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerAssignableHandlers(Class<? extends RestController> parent, RestController parentValue, Method method) {
|
||||||
|
if (
|
||||||
|
(parent.isAnnotationPresent(GlobalControllerManifest.class)) &&
|
||||||
|
(method.isAnnotationPresent(ScopedControllerManifest.class))
|
||||||
|
) {
|
||||||
|
HandlerType handlerType = method.getAnnotation(ScopedControllerManifest.class).method();
|
||||||
|
|
||||||
|
String path = PathBuilder.resolvePathOf(
|
||||||
|
parent.getAnnotation(GlobalControllerManifest.class).path(),
|
||||||
|
method.getAnnotation(ScopedControllerManifest.class).path()
|
||||||
|
);
|
||||||
|
|
||||||
|
switch (handlerType) {
|
||||||
|
case GET:
|
||||||
|
Spark.get(path, (request, response) -> method.invoke(parentValue, request, response));
|
||||||
|
break;
|
||||||
|
case PUT:
|
||||||
|
Spark.put(path, (request, response) -> method.invoke(parentValue, request, response));
|
||||||
|
break;
|
||||||
|
case POST:
|
||||||
|
Spark.post(path, (request, response) -> method.invoke(parentValue, request, response));
|
||||||
|
break;
|
||||||
|
case DELETE:
|
||||||
|
Spark.delete(path, (request, response) -> method.invoke(parentValue, request, response));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.r11.tools.controller.internal;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
public @interface ScopedControllerManifest {
|
||||||
|
|
||||||
|
HandlerType method();
|
||||||
|
|
||||||
|
String path();
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.r11.tools.controller.internal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class used to store data received from parser and type of that data (node, string, etc.)
|
||||||
|
*/
|
||||||
|
public class XPathQueryResult {
|
||||||
|
private String data;
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
public XPathQueryResult(String data, String type) {
|
||||||
|
this.data = data;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.r11.tools.controller.internal.path;
|
||||||
|
|
||||||
|
public final class PathBuilder {
|
||||||
|
|
||||||
|
private static final String PATH_SEPARATOR = "/";
|
||||||
|
|
||||||
|
private PathBuilder() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String resolvePathOf(String globalPath, String scopedPath) {
|
||||||
|
String resolvedPath =
|
||||||
|
PathBuilder.removeTrailingPathSeparator(globalPath) +
|
||||||
|
PathBuilder.removeTrailingPathSeparator(scopedPath);
|
||||||
|
|
||||||
|
if (resolvedPath.endsWith(PATH_SEPARATOR)) {
|
||||||
|
resolvedPath = resolvedPath.substring(0, resolvedPath.length() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return PATH_SEPARATOR + resolvedPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String removeTrailingPathSeparator(String path) {
|
||||||
|
if (path.endsWith(PATH_SEPARATOR)) {
|
||||||
|
return path.substring(0, path.length() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
package r11.mltx.restxslt.processors;
|
package com.r11.tools.xml;
|
||||||
|
|
||||||
import net.sf.saxon.om.NamespaceBinding;
|
|
||||||
import net.sf.saxon.om.NamespaceMap;
|
import net.sf.saxon.om.NamespaceMap;
|
||||||
import net.sf.saxon.s9api.XPathCompiler;
|
import net.sf.saxon.s9api.XPathCompiler;
|
||||||
import net.sf.saxon.s9api.XdmNode;
|
import net.sf.saxon.s9api.XdmNode;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
import java.util.Iterator;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for saxon namespace scan engine.
|
* Handler for saxon namespace scan engine.
|
||||||
@@ -13,6 +12,7 @@ import java.util.Iterator;
|
|||||||
* @author Wojciech Czop
|
* @author Wojciech Czop
|
||||||
*/
|
*/
|
||||||
public class NewNamespaceResolver {
|
public class NewNamespaceResolver {
|
||||||
|
private static final Logger LOG = LogManager.getLogger("NewNamespaceResolver");
|
||||||
|
|
||||||
private NamespaceMap namespaceMap;
|
private NamespaceMap namespaceMap;
|
||||||
|
|
||||||
@@ -21,12 +21,13 @@ public class NewNamespaceResolver {
|
|||||||
* @param doc dom structure object
|
* @param doc dom structure object
|
||||||
* @return map of namespaces
|
* @return map of namespaces
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// TODO: Closer inspection. Return value is never used according to IntelliJ
|
||||||
|
//
|
||||||
public NamespaceMap process(XdmNode doc) {
|
public NamespaceMap process(XdmNode doc) {
|
||||||
namespaceMap = NamespaceMap.emptyMap();
|
namespaceMap = NamespaceMap.emptyMap();
|
||||||
Iterator<XdmNode> it = doc.children().iterator();
|
// TODO: remove
|
||||||
// TODO: remove
|
for (XdmNode tmp : doc.children()) {
|
||||||
while (it.hasNext()) {
|
|
||||||
XdmNode tmp = it.next();
|
|
||||||
extractNamespace(tmp);
|
extractNamespace(tmp);
|
||||||
}
|
}
|
||||||
// end
|
// end
|
||||||
@@ -38,12 +39,6 @@ public class NewNamespaceResolver {
|
|||||||
* @param compiler compiler used to compile xpath statements
|
* @param compiler compiler used to compile xpath statements
|
||||||
*/
|
*/
|
||||||
public void exportNamespaces(XPathCompiler compiler){
|
public void exportNamespaces(XPathCompiler compiler){
|
||||||
Iterator<NamespaceBinding> it = namespaceMap.iterator();
|
|
||||||
// TODO: remove
|
|
||||||
while(it.hasNext()){
|
|
||||||
System.out.println(it.next());
|
|
||||||
}
|
|
||||||
// end
|
|
||||||
namespaceMap.forEach(namespaceBinding -> compiler.declareNamespace(namespaceBinding.getPrefix(), namespaceBinding.getURI()));
|
namespaceMap.forEach(namespaceBinding -> compiler.declareNamespace(namespaceBinding.getPrefix(), namespaceBinding.getURI()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,17 +53,11 @@ public class NewNamespaceResolver {
|
|||||||
}
|
}
|
||||||
if (node.children().iterator().hasNext()) {
|
if (node.children().iterator().hasNext()) {
|
||||||
|
|
||||||
Iterator<XdmNode> it = node.children().iterator();
|
for (XdmNode rNode : node.children()) {
|
||||||
while (it.hasNext()) {
|
if (rNode.getUnderlyingNode().getPrefix().isEmpty() && !rNode.getParent().getUnderlyingNode().getPrefix().isEmpty()) {
|
||||||
XdmNode rNode = it.next();
|
LOG.warn("Missing prefix. Parent has " + rNode.getParent().getUnderlyingNode().getPrefix() + ", but child has none");
|
||||||
// TODO: remove
|
|
||||||
if(rNode.getUnderlyingNode().getPrefix().isEmpty() && !rNode.getParent().getUnderlyingNode().getPrefix().isEmpty()){
|
|
||||||
|
|
||||||
System.out.println("prefix missing, parent has "+rNode.getParent().getUnderlyingNode().getPrefix() + ", but child has none");
|
|
||||||
|
|
||||||
System.out.println();
|
|
||||||
}
|
}
|
||||||
// end
|
|
||||||
extractNamespace(rNode);
|
extractNamespace(rNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package r11.mltx.restxslt.processors;
|
package com.r11.tools.xml;
|
||||||
|
|
||||||
|
import com.r11.tools.controller.internal.XPathQueryResult;
|
||||||
import net.sf.saxon.s9api.*;
|
import net.sf.saxon.s9api.*;
|
||||||
|
|
||||||
import javax.xml.transform.stream.StreamSource;
|
import javax.xml.transform.stream.StreamSource;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
@@ -9,7 +11,7 @@ import java.io.StringWriter;
|
|||||||
* Handler for Saxon engine
|
* Handler for Saxon engine
|
||||||
* @author Wojciech Czop
|
* @author Wojciech Czop
|
||||||
*/
|
*/
|
||||||
public class Saxon {
|
public class Saxon implements XmlEngine{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms string containing xml document via xslt
|
* Transforms string containing xml document via xslt
|
||||||
@@ -18,7 +20,7 @@ public class Saxon {
|
|||||||
* @return transformed xml
|
* @return transformed xml
|
||||||
* @throws SaxonApiException thrown on stylesheet or transformation errors
|
* @throws SaxonApiException thrown on stylesheet or transformation errors
|
||||||
*/
|
*/
|
||||||
public static String processXSLT(String data, String transform) throws SaxonApiException {
|
public String processXSLT(String data, String transform) throws SaxonApiException {
|
||||||
Processor processor = new Processor(false);
|
Processor processor = new Processor(false);
|
||||||
XsltCompiler compiler = processor.newXsltCompiler();
|
XsltCompiler compiler = processor.newXsltCompiler();
|
||||||
XsltExecutable stylesheet = compiler.compile(new StreamSource(new StringReader(transform)));
|
XsltExecutable stylesheet = compiler.compile(new StreamSource(new StringReader(transform)));
|
||||||
@@ -32,6 +34,11 @@ public class Saxon {
|
|||||||
return sw.toString();
|
return sw.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String validate(String data, String xsd) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process xpath and return either node or wrapped atomic value
|
* Process xpath and return either node or wrapped atomic value
|
||||||
* @param data xml to be querried
|
* @param data xml to be querried
|
||||||
@@ -40,7 +47,7 @@ public class Saxon {
|
|||||||
* @return string xml representation of the node
|
* @return string xml representation of the node
|
||||||
* @throws Exception thrown on node building errors or invalid xpath
|
* @throws Exception thrown on node building errors or invalid xpath
|
||||||
*/
|
*/
|
||||||
public static String processXPath(String data, String query, String version) throws Exception {
|
public XPathQueryResult processXPath(String data, String query, String version) throws Exception {
|
||||||
Processor p = new Processor(false);
|
Processor p = new Processor(false);
|
||||||
XPathCompiler compiler = p.newXPathCompiler();
|
XPathCompiler compiler = p.newXPathCompiler();
|
||||||
DocumentBuilder builder = p.newDocumentBuilder();
|
DocumentBuilder builder = p.newDocumentBuilder();
|
||||||
@@ -60,7 +67,7 @@ public class Saxon {
|
|||||||
sb.append(xdmItem);
|
sb.append(xdmItem);
|
||||||
sb.append('\n');
|
sb.append('\n');
|
||||||
}
|
}
|
||||||
return sb.toString();
|
return new XPathQueryResult(sb.toString(), "N/A");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +75,7 @@ public class Saxon {
|
|||||||
* Returns version of the processor
|
* Returns version of the processor
|
||||||
* @return version of the processor
|
* @return version of the processor
|
||||||
*/
|
*/
|
||||||
public static String getVersion() {
|
public String getVersion() {
|
||||||
return new Processor(false).getSaxonProductVersion();
|
return new Processor(false).getSaxonProductVersion();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
package com.r11.tools.xml;
|
||||||
|
|
||||||
|
import com.r11.tools.controller.internal.XPathQueryResult;
|
||||||
|
import org.apache.xpath.XPathAPI;
|
||||||
|
import org.apache.xpath.objects.XObject;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
import org.w3c.dom.traversal.NodeIterator;
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
|
|
||||||
|
import javax.xml.XMLConstants;
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.transform.*;
|
||||||
|
import javax.xml.transform.dom.DOMSource;
|
||||||
|
import javax.xml.transform.stream.StreamResult;
|
||||||
|
import javax.xml.transform.stream.StreamSource;
|
||||||
|
import javax.xml.validation.Schema;
|
||||||
|
import javax.xml.validation.SchemaFactory;
|
||||||
|
import javax.xml.validation.Validator;
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for Xalan engine
|
||||||
|
* @author Wojciech Czop
|
||||||
|
*/
|
||||||
|
public class Xalan implements XmlEngine{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms string containing xml document via xslt
|
||||||
|
* @param data xml to be transformed
|
||||||
|
* @param transform xslt
|
||||||
|
* @return transformed xml
|
||||||
|
* @throws Exception thrown on stylesheet or transformation errors
|
||||||
|
*/
|
||||||
|
public String processXSLT(String data, String transform) throws Exception {
|
||||||
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||||
|
Document document = builder.parse(new InputSource(new StringReader(data)));
|
||||||
|
|
||||||
|
StreamSource stylesource = new StreamSource(new StringReader(transform));
|
||||||
|
Transformer transformer = TransformerFactory.newInstance().newTransformer(stylesource);
|
||||||
|
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
|
||||||
|
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||||
|
|
||||||
|
Source source = new DOMSource(document);
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
Result outputTarget = new StreamResult(sw);
|
||||||
|
transformer.transform(source, outputTarget);
|
||||||
|
|
||||||
|
return sw.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTextNode(Node n) {
|
||||||
|
if (n == null)
|
||||||
|
return false;
|
||||||
|
short nodeType = n.getNodeType();
|
||||||
|
return nodeType == Node.CDATA_SECTION_NODE || nodeType == Node.TEXT_NODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process xpath and return either node or wrapped atomic value
|
||||||
|
* @param data xml
|
||||||
|
* @param transform xpath
|
||||||
|
* @return xml processed using given xpath
|
||||||
|
* @throws Exception thrown on node building errors or invalid xpath
|
||||||
|
*/
|
||||||
|
public XPathQueryResult processXPath(String data, String transform, String version) throws Exception {
|
||||||
|
|
||||||
|
// Set up a DOM tree to query.
|
||||||
|
InputSource in = new InputSource(new StringReader(data));
|
||||||
|
DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
|
||||||
|
dfactory.setNamespaceAware(true);
|
||||||
|
Document doc = dfactory.newDocumentBuilder().parse(in);
|
||||||
|
|
||||||
|
// Set up an identity transformer to use as serializer.
|
||||||
|
Transformer serializer = TransformerFactory.newInstance().newTransformer();
|
||||||
|
serializer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
|
||||||
|
|
||||||
|
// Use the simple XPath API to select a nodeIterator.
|
||||||
|
try {
|
||||||
|
NodeIterator nl = XPathAPI.selectNodeIterator(doc, transform);
|
||||||
|
|
||||||
|
// Serialize the found nodes to result object.
|
||||||
|
StringBuilder resultString = new StringBuilder();
|
||||||
|
Node n;
|
||||||
|
while ((n = nl.nextNode())!= null) {
|
||||||
|
StringBuilder sb;
|
||||||
|
if (isTextNode(n)) {
|
||||||
|
// DOM may have more than one node corresponding to a
|
||||||
|
// single XPath text node. Coalesce all contiguous text nodes
|
||||||
|
// at this level
|
||||||
|
for (Node nn = n.getNextSibling(); isTextNode(nn); nn = nn.getNextSibling()) {
|
||||||
|
resultString.append(nn.getNodeValue());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
|
serializer.transform(new DOMSource(n), new StreamResult(new OutputStreamWriter(outputStream)));
|
||||||
|
resultString.append(outputStream);
|
||||||
|
}
|
||||||
|
resultString.append("\n");
|
||||||
|
}
|
||||||
|
return new XPathQueryResult(resultString.toString(), "node");
|
||||||
|
} catch (TransformerException e) {
|
||||||
|
String returnData = XPathAPI.eval(doc, transform).toString();
|
||||||
|
return new XPathQueryResult(returnData, "string");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns version of the processor
|
||||||
|
* @return version of the processor
|
||||||
|
*/
|
||||||
|
public String getVersion(){
|
||||||
|
return org.apache.xalan.Version.getVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates string representation of the xml document against xsd schema
|
||||||
|
* @param data xml document
|
||||||
|
* @param xsd xsd schema
|
||||||
|
* @return statement of validity
|
||||||
|
* @throws Exception thrown on invalid xsd schema or xml
|
||||||
|
*/
|
||||||
|
public String validate(String data, String xsd) throws Exception {
|
||||||
|
Source dataSource = new StreamSource(new StringReader(data));
|
||||||
|
Source xsdSource = new StreamSource(new StringReader(xsd));
|
||||||
|
SchemaFactory schemaFactory = SchemaFactory
|
||||||
|
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
||||||
|
Schema schema = schemaFactory.newSchema(xsdSource);
|
||||||
|
Validator validator = schema.newValidator();
|
||||||
|
validator.validate(dataSource);
|
||||||
|
return "XML file is valid";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package r11.mltx.restxslt.processors;
|
package com.r11.tools.xml;
|
||||||
|
|
||||||
import org.w3c.dom.*;
|
import org.w3c.dom.*;
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.r11.tools.xml;
|
||||||
|
|
||||||
|
import com.r11.tools.controller.internal.XPathQueryResult;
|
||||||
|
|
||||||
|
public interface XmlEngine {
|
||||||
|
XPathQueryResult processXPath(String data, String query, String version) throws Exception;
|
||||||
|
String processXSLT(String data, String transform) throws Exception;
|
||||||
|
String validate(String data, String xsd) throws Exception;
|
||||||
|
|
||||||
|
public String getVersion();
|
||||||
|
|
||||||
|
}
|
||||||
21
Backend/tools-services/src/main/resources/log4j2.xml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Configuration status="WARN">
|
||||||
|
<Appenders>
|
||||||
|
<Console name="Console" target="SYSTEM_OUT">
|
||||||
|
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%c] %-5level - %msg%n"/>
|
||||||
|
</Console>
|
||||||
|
<File name="File" fileName="/tmp/xml_tools_java_backend.log" append="true">
|
||||||
|
<PatternLayout>
|
||||||
|
<Pattern>%d{HH:mm:ss.SSS} [%c] %-5level - %msg%n</Pattern>
|
||||||
|
</PatternLayout>
|
||||||
|
</File>
|
||||||
|
</Appenders>
|
||||||
|
<Loggers>
|
||||||
|
<Logger name="com.r11.tools.SparkApplication" level="info" additivity="true">
|
||||||
|
<AppenderRef ref="Console"/>
|
||||||
|
</Logger>
|
||||||
|
<Root level="info">
|
||||||
|
<AppenderRef ref="File"/>
|
||||||
|
</Root>
|
||||||
|
</Loggers>
|
||||||
|
</Configuration>
|
||||||
2
Filebeat/Dockerfile
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
FROM docker.elastic.co/beats/filebeat:8.6.2
|
||||||
|
COPY --chown=root:filebeat filebeat.docker.yml /usr/share/filebeat/filebeat.yml
|
||||||
21
Filebeat/filebeat.docker.yml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
filebeat.config:
|
||||||
|
modules:
|
||||||
|
path: ${path.config}/modules.d/*.yml
|
||||||
|
reload.enabled: false
|
||||||
|
|
||||||
|
filebeat.autodiscover:
|
||||||
|
providers:
|
||||||
|
- type: docker
|
||||||
|
hints.enabled: true
|
||||||
|
|
||||||
|
processors:
|
||||||
|
- add_cloud_metadata: ~
|
||||||
|
|
||||||
|
output.elasticsearch:
|
||||||
|
hosts: '${ELASTICSEARCH_HOSTS:elc-0.zipper.release11.com:9200}'
|
||||||
|
index: 'xmltools-${ENV_TYPE:dev}-%{+YYYY.MM}'
|
||||||
|
|
||||||
|
|
||||||
|
setup.template:
|
||||||
|
name: "xmltools"
|
||||||
|
pattern: "xmltools-*"
|
||||||
20
Frontend/Dockerfile
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
FROM nginx:stable-alpine
|
||||||
|
|
||||||
|
RUN apk add --no-cache tzdata
|
||||||
|
ENV TZ Europe/Warsaw
|
||||||
|
|
||||||
|
COPY ./tools/ /usr/share/nginx/html/tools/
|
||||||
|
COPY ./lawful/ /usr/share/nginx/html/lawful/
|
||||||
|
COPY ./assets/ /usr/share/nginx/html/assets/
|
||||||
|
COPY ./index.html /usr/share/nginx/html
|
||||||
|
COPY ./nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
|
RUN mkdir -p /scripts
|
||||||
|
COPY insert_version.sh /scripts/
|
||||||
|
WORKDIR /scripts
|
||||||
|
|
||||||
|
RUN chmod +x insert_version.sh
|
||||||
|
RUN ./insert_version.sh
|
||||||
|
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
6
Frontend/assets/css/common/common.css
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
@import url('https://necolas.github.io/normalize.css/8.0.1/normalize.css');
|
||||||
|
@import url('r11addons.css');
|
||||||
|
@import url('r11tables.css');
|
||||||
|
@import url('r11tool.css');
|
||||||
|
@import url('r11tooltip.css');
|
||||||
|
@import url('r11modal.css');
|
||||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
150
Frontend/assets/css/frame.css
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: "Nunito";
|
||||||
|
src: url('../fonts/Nunito-VariableFont_wght.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
background-image: url("../images/background.jpg");
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Nunito', sans-serif;
|
||||||
|
font-weight: 200;
|
||||||
|
|
||||||
|
color: #2e3133;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#header {
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
width: 100%;
|
||||||
|
height: 80px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
#logo {
|
||||||
|
padding: 20px 20px 20px;
|
||||||
|
width: 250px;
|
||||||
|
grid-column: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iframe#iframe {
|
||||||
|
flex-grow: 1;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#content {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 80px);
|
||||||
|
display: flex;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
div#leftBar {
|
||||||
|
float: left;
|
||||||
|
width: 200px;
|
||||||
|
background-color: transparent;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#copyright{
|
||||||
|
color:rgb(192, 192, 192);
|
||||||
|
position: fixed;
|
||||||
|
bottom: 10px;
|
||||||
|
width: 200px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#copyright a, a:visited, a:active {
|
||||||
|
color: rgb(192, 192, 192);
|
||||||
|
}
|
||||||
|
|
||||||
|
#toolList {
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 10px 0 0 0;
|
||||||
|
overflow: hidden;
|
||||||
|
display: block;
|
||||||
|
float: left;
|
||||||
|
background-color: transparent;
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 80px);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolListRow a {
|
||||||
|
display: block;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px 50px 25px;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolListRow a:hover {
|
||||||
|
background-color: #2A93B0;
|
||||||
|
color: white;
|
||||||
|
transform: scale(1.25, 1.25);
|
||||||
|
transition-duration: .3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#leftElements {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#titlebar {
|
||||||
|
/* padding: 10px 0; */
|
||||||
|
color: black;
|
||||||
|
height: fit-content;
|
||||||
|
margin: 0px 20px;
|
||||||
|
font-size: 36px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
}
|
||||||
|
#menu {
|
||||||
|
display: flex;
|
||||||
|
height: fit-content;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu a {
|
||||||
|
display: block;
|
||||||
|
margin: 0px 10px;
|
||||||
|
padding: 0px 10px;
|
||||||
|
font-size: 28px;
|
||||||
|
text-decoration: none;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu a.active {
|
||||||
|
border-bottom: 3px solid #2A93B0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu a:hover {
|
||||||
|
transform: scale(1.25, 1.25);
|
||||||
|
transition-duration: .3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator{
|
||||||
|
width: 100%;
|
||||||
|
padding:6px;
|
||||||
|
}
|
||||||
69
Frontend/assets/css/highlight.css
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
.json-block {
|
||||||
|
height: 600px;
|
||||||
|
width: 97%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.json-border {
|
||||||
|
border: 2px solid rgba(93, 99, 96, 0.705);
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.json-border:focus {
|
||||||
|
box-shadow: 0 0 5px rgb(81, 203, 238);
|
||||||
|
border: 2px solid rgba(93, 99, 96, 0.705);
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Theme: Default Description: Original highlight.js style Author: (c) Ivan Sagalaev <maniac@softwaremaniacs.org> Maintainer: @highlightjs/core-team Website: https://highlightjs.org/ License: see project LICENSE Touched: 2021 */
|
||||||
|
pre code.hljs{
|
||||||
|
display:block;
|
||||||
|
overflow-x:auto;
|
||||||
|
padding:1em
|
||||||
|
}
|
||||||
|
code.hljs{
|
||||||
|
padding:3px 5px
|
||||||
|
}
|
||||||
|
.hljs{
|
||||||
|
background:#FFFFFF;
|
||||||
|
color:#444
|
||||||
|
}
|
||||||
|
.hljs-comment{
|
||||||
|
color:#697070
|
||||||
|
}
|
||||||
|
.hljs-punctuation,.hljs-tag{
|
||||||
|
color:#444a
|
||||||
|
}
|
||||||
|
.hljs-tag .hljs-attr,.hljs-tag .hljs-name{
|
||||||
|
color:#444
|
||||||
|
}
|
||||||
|
.hljs-attribute,.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-name,.hljs-selector-tag{
|
||||||
|
font-weight:700
|
||||||
|
}
|
||||||
|
.hljs-deletion,.hljs-number,.hljs-quote,.hljs-selector-class,.hljs-selector-id,.hljs-string,.hljs-template-tag,.hljs-type{
|
||||||
|
color:#800
|
||||||
|
}
|
||||||
|
.hljs-section,.hljs-title{
|
||||||
|
color:#800;
|
||||||
|
font-weight:700
|
||||||
|
}
|
||||||
|
.hljs-link,.hljs-operator,.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-symbol,.hljs-template-variable,.hljs-variable{
|
||||||
|
color:#ab5656
|
||||||
|
}
|
||||||
|
.hljs-literal{
|
||||||
|
color:#695
|
||||||
|
}
|
||||||
|
.hljs-addition,.hljs-built_in,.hljs-bullet,.hljs-code{
|
||||||
|
color:#397300
|
||||||
|
}
|
||||||
|
.hljs-meta{
|
||||||
|
color:#1f7199
|
||||||
|
}
|
||||||
|
.hljs-meta .hljs-string{
|
||||||
|
color:#38a
|
||||||
|
}
|
||||||
|
.hljs-emphasis{
|
||||||
|
font-style:italic
|
||||||
|
}
|
||||||
|
.hljs-strong{
|
||||||
|
font-weight:700
|
||||||
|
}
|
||||||
42
Frontend/assets/css/lawful.css
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@200&display=swap');
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: "Nunito", sans-serif;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
margin: 0px;
|
||||||
|
|
||||||
|
}
|
||||||
|
h1, h2 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2::before {
|
||||||
|
background: url('/assets/images/sygnet_color.svg') no-repeat;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header {
|
||||||
|
height: 80px;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#logo {
|
||||||
|
width: 250px;
|
||||||
|
margin: 0px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content {
|
||||||
|
width: 1024px;
|
||||||
|
margin: auto;
|
||||||
|
text-align: justify;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
padding: 20px 20px;
|
||||||
|
border-radius: 15px;
|
||||||
|
margin-top: 100px;
|
||||||
|
}
|
||||||
BIN
Frontend/assets/css/tools/font/fontello.eot
Normal file
14
Frontend/assets/css/tools/font/fontello.svg
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<metadata>Copyright (C) 2021 by original authors @ fontello.com</metadata>
|
||||||
|
<defs>
|
||||||
|
<font id="fontello" horiz-adv-x="1000" >
|
||||||
|
<font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
|
||||||
|
<missing-glyph horiz-adv-x="1000" />
|
||||||
|
<glyph glyph-name="plus" unicode="" d="M786 439v-107q0-22-16-38t-38-15h-232v-233q0-22-16-37t-38-16h-107q-22 0-38 16t-15 37v233h-232q-23 0-38 15t-16 38v107q0 23 16 38t38 16h232v232q0 22 15 38t38 16h107q23 0 38-16t16-38v-232h232q23 0 38-16t16-38z" horiz-adv-x="785.7" />
|
||||||
|
|
||||||
|
<glyph glyph-name="cancel" unicode="" d="M724 112q0-22-15-38l-76-76q-16-15-38-15t-38 15l-164 165-164-165q-16-15-38-15t-38 15l-76 76q-16 16-16 38t16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38z" horiz-adv-x="785.7" />
|
||||||
|
</font>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Frontend/assets/css/tools/font/fontello.ttf
Normal file
BIN
Frontend/assets/css/tools/font/fontello.woff
Normal file
BIN
Frontend/assets/css/tools/font/fontello.woff2
Normal file
59
Frontend/assets/css/tools/fontello.css
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'fontello';
|
||||||
|
src: url('font/fontello.eot?49304387');
|
||||||
|
src: url('font/fontello.eot?49304387#iefix') format('embedded-opentype'),
|
||||||
|
url('font/fontello.woff2?49304387') format('woff2'),
|
||||||
|
url('font/fontello.woff?49304387') format('woff'),
|
||||||
|
url('font/fontello.ttf?49304387') format('truetype'),
|
||||||
|
url('font/fontello.svg?49304387#fontello') format('svg');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
|
||||||
|
/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
|
||||||
|
/*
|
||||||
|
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||||
|
@font-face {
|
||||||
|
font-family: 'fontello';
|
||||||
|
src: url('../font/fontello.svg?49304387#fontello') format('svg');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
[class^="icon-"]:before, [class*=" icon-"]:before {
|
||||||
|
font-family: "fontello";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: normal;
|
||||||
|
speak: never;
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: inherit;
|
||||||
|
width: 1em;
|
||||||
|
margin-right: .2em;
|
||||||
|
text-align: center;
|
||||||
|
/* opacity: .8; */
|
||||||
|
|
||||||
|
/* For safety - reset parent styles, that can break glyph codes*/
|
||||||
|
font-variant: normal;
|
||||||
|
text-transform: none;
|
||||||
|
|
||||||
|
/* fix buttons height, for twitter bootstrap */
|
||||||
|
line-height: 1em;
|
||||||
|
|
||||||
|
/* Animation center compensation - margins should be symmetric */
|
||||||
|
/* remove if not needed */
|
||||||
|
margin-left: .2em;
|
||||||
|
|
||||||
|
/* you can be more comfortable with increased icons size */
|
||||||
|
/* font-size: 120%; */
|
||||||
|
|
||||||
|
/* Font smoothing. That was taken from TWBS */
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
|
/* Uncomment for 3D effect */
|
||||||
|
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-plus:before { content: '\e801'; } /* '' */
|
||||||
|
.icon-cancel:before { content: '\e802'; } /* '' */
|
||||||
34
Frontend/assets/css/tools/mock/common.css
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
@import url('https://necolas.github.io/normalize.css/8.0.1/normalize.css');
|
||||||
|
/* @import url('https://fonts.googleapis.com/icon?family=Material+Icons'); */
|
||||||
|
@import url('r11addons.css');
|
||||||
|
@import url('r11tables.css');
|
||||||
|
@import url('r11tool.css');
|
||||||
|
@import url('r11tooltip.css');
|
||||||
|
@import url('r11modal.css');
|
||||||
|
@import url('r11flexbox.css');
|
||||||
|
@import url('r11popup.css');
|
||||||
|
@import url('../../highlight.css');
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Material Icons';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: url(https://fonts.gstatic.com/s/materialicons/v140/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-icons {
|
||||||
|
font-family: 'Material Icons';
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 1;
|
||||||
|
letter-spacing: normal;
|
||||||
|
text-transform: none;
|
||||||
|
display: inline-block;
|
||||||
|
white-space: nowrap;
|
||||||
|
word-wrap: normal;
|
||||||
|
direction: ltr;
|
||||||
|
-moz-font-feature-settings: 'liga';
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
BIN
Frontend/assets/css/tools/mock/font/Material-Icons.woff2
Normal file
BIN
Frontend/assets/css/tools/mock/font/Nunito-VariableFont_wght.ttf
Normal file
BIN
Frontend/assets/css/tools/mock/font/fontello.eot
Normal file
14
Frontend/assets/css/tools/mock/font/fontello.svg
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<metadata>Copyright (C) 2021 by original authors @ fontello.com</metadata>
|
||||||
|
<defs>
|
||||||
|
<font id="fontello" horiz-adv-x="1000" >
|
||||||
|
<font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
|
||||||
|
<missing-glyph horiz-adv-x="1000" />
|
||||||
|
<glyph glyph-name="plus" unicode="" d="M786 439v-107q0-22-16-38t-38-15h-232v-233q0-22-16-37t-38-16h-107q-22 0-38 16t-15 37v233h-232q-23 0-38 15t-16 38v107q0 23 16 38t38 16h232v232q0 22 15 38t38 16h107q23 0 38-16t16-38v-232h232q23 0 38-16t16-38z" horiz-adv-x="785.7" />
|
||||||
|
|
||||||
|
<glyph glyph-name="cancel" unicode="" d="M724 112q0-22-15-38l-76-76q-16-15-38-15t-38 15l-164 165-164-165q-16-15-38-15t-38 15l-76 76q-16 16-16 38t16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38z" horiz-adv-x="785.7" />
|
||||||
|
</font>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Frontend/assets/css/tools/mock/font/fontello.ttf
Normal file
BIN
Frontend/assets/css/tools/mock/font/fontello.woff
Normal file
BIN
Frontend/assets/css/tools/mock/font/fontello.woff2
Normal file
59
Frontend/assets/css/tools/mock/fontello.css
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'fontello';
|
||||||
|
src: url('font/fontello.eot?49304387');
|
||||||
|
src: url('font/fontello.eot?49304387#iefix') format('embedded-opentype'),
|
||||||
|
url('font/fontello.woff2?49304387') format('woff2'),
|
||||||
|
url('font/fontello.woff?49304387') format('woff'),
|
||||||
|
url('font/fontello.ttf?49304387') format('truetype'),
|
||||||
|
url('font/fontello.svg?49304387#fontello') format('svg');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
|
||||||
|
/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
|
||||||
|
/*
|
||||||
|
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||||
|
@font-face {
|
||||||
|
font-family: 'fontello';
|
||||||
|
src: url('../font/fontello.svg?49304387#fontello') format('svg');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
[class^="icon-"]:before, [class*=" icon-"]:before {
|
||||||
|
font-family: "fontello";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: normal;
|
||||||
|
speak: never;
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: inherit;
|
||||||
|
width: 1em;
|
||||||
|
margin-right: .2em;
|
||||||
|
text-align: center;
|
||||||
|
/* opacity: .8; */
|
||||||
|
|
||||||
|
/* For safety - reset parent styles, that can break glyph codes*/
|
||||||
|
font-variant: normal;
|
||||||
|
text-transform: none;
|
||||||
|
|
||||||
|
/* fix buttons height, for twitter bootstrap */
|
||||||
|
line-height: 1em;
|
||||||
|
|
||||||
|
/* Animation center compensation - margins should be symmetric */
|
||||||
|
/* remove if not needed */
|
||||||
|
margin-left: .2em;
|
||||||
|
|
||||||
|
/* you can be more comfortable with increased icons size */
|
||||||
|
/* font-size: 120%; */
|
||||||
|
|
||||||
|
/* Font smoothing. That was taken from TWBS */
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
|
/* Uncomment for 3D effect */
|
||||||
|
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-plus:before { content: '\e801'; } /* '' */
|
||||||
|
.icon-cancel:before { content: '\e802'; } /* '' */
|
||||||
4
Frontend/assets/css/tools/mock/main.css
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
.overflowedTableContent {
|
||||||
|
max-height: 750px;
|
||||||
|
overflow: scroll;
|
||||||
|
}
|
||||||
95
Frontend/assets/css/tools/mock/r11addons.css
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
.modification-button.btn-tile:hover {
|
||||||
|
color: #ca1111;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modification-button.btn-tile {
|
||||||
|
width: 10%;
|
||||||
|
margin: 20% 0 0 0;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #00000020
|
||||||
|
}
|
||||||
|
|
||||||
|
.modification-button.btn-addtile {
|
||||||
|
font-size: 38px;
|
||||||
|
color: #00000030;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modification-button.btn-copy {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
align-content: center;
|
||||||
|
display: grid;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modification-button.btn-copy img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modification-button.btn-addtile:hover {
|
||||||
|
color: #58ac43;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tile {
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 40%;
|
||||||
|
border-radius: 5px;
|
||||||
|
position: relative;
|
||||||
|
background: #D5D7E6;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
cursor: default;
|
||||||
|
border-bottom: 1px solid darkgray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tile:hover {
|
||||||
|
filter: brightness(110%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tile.active {
|
||||||
|
background: #2A93B0;
|
||||||
|
color: white;
|
||||||
|
filter: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tile.active .btn-tile {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tile .content {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
padding: 0 2% 0 7%;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content p {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refresh-button{
|
||||||
|
float: right;
|
||||||
|
border: none;
|
||||||
|
background-color: unset;
|
||||||
|
font-size: xx-large;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refresh-button:hover{
|
||||||
|
animation-name: rotation;
|
||||||
|
animation-duration: 0.8s;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotation{
|
||||||
|
from{
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
57
Frontend/assets/css/tools/mock/r11flexbox.css
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#editable-block {
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#uuid-edit {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#uuid-edit-field {
|
||||||
|
display: flex;
|
||||||
|
width: fit-content;
|
||||||
|
align-items: center;
|
||||||
|
width: 70%;
|
||||||
|
margin-right: 10px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#uuid-edit-field .uuid-inputField-icon{
|
||||||
|
background: none;
|
||||||
|
color: black;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#uuid-edit-field .uuid-inputField-icon:hover{
|
||||||
|
color: #2A93B0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#uuid-input {
|
||||||
|
border: none;
|
||||||
|
width: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
#uuid-input:focus {
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#uuid-validation-strategy input {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disabled {
|
||||||
|
background-color: #CCD1CF;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.disabled #uuid-input {
|
||||||
|
background-color: #CCD1CF;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.uuid-inputField-icon-span {
|
||||||
|
font-size: x-large;
|
||||||
|
}
|
||||||
104
Frontend/assets/css/tools/mock/r11modal.css
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#overlay {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
opacity: 0;
|
||||||
|
background: rgba(0, 0 , 0, 0.5);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#overlay.active {
|
||||||
|
pointer-events: all;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
display: none;
|
||||||
|
width: 390px;
|
||||||
|
min-height: 71px;
|
||||||
|
max-height: 700px;
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
background: white;
|
||||||
|
padding: 5px;
|
||||||
|
border: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal div.header {
|
||||||
|
width: 384px;
|
||||||
|
height: 24px;
|
||||||
|
background: #2e3133;
|
||||||
|
color: white;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 3px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal div.header button {
|
||||||
|
font-size: 100%;
|
||||||
|
font-family: inherit;
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
background: 0;
|
||||||
|
color: inherit;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal div.header button:hover {
|
||||||
|
color: white;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal div.body {
|
||||||
|
width: 370px;
|
||||||
|
padding: 10px;
|
||||||
|
background: #f0f0f0;
|
||||||
|
color: #2e3133;
|
||||||
|
min-height: 16px;
|
||||||
|
text-align: justify;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal div.function {
|
||||||
|
width: 385px;
|
||||||
|
min-height: 30px;
|
||||||
|
padding-top: 5px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
background: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal div.function button {
|
||||||
|
min-height: 22px;
|
||||||
|
min-width: 34px;
|
||||||
|
max-width: 74px;
|
||||||
|
padding: 3px 20px;
|
||||||
|
outline: none;
|
||||||
|
border: 1px solid #f0f0f0;
|
||||||
|
background: rgba(205,205,205,1);
|
||||||
|
font-size: 16px;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal div.function button:hover {
|
||||||
|
filter: brightness(110%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.r-exclamation:before {
|
||||||
|
content: '!';
|
||||||
|
color: #3bc4f1;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
83
Frontend/assets/css/tools/mock/r11popup.css
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
.popup-flex:not(.hiddable-container){
|
||||||
|
animation: blur 0.5s ease-in-out ;
|
||||||
|
animation-fill-mode: forwards;
|
||||||
|
}
|
||||||
|
.popup-flex{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 50;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2%;
|
||||||
|
position: fixed;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-body{
|
||||||
|
min-width: 33%;
|
||||||
|
max-width: 60%;
|
||||||
|
max-height: 70%;
|
||||||
|
background-color: white;
|
||||||
|
box-shadow: 10px 10px 5px lightblue;
|
||||||
|
min-height: 45%;
|
||||||
|
border-radius: 1em;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px 15px 15px 15px;
|
||||||
|
color: black;
|
||||||
|
border: 1px #2A93B0 solid;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-button-close-container{
|
||||||
|
text-align: right;
|
||||||
|
margin-right: 2%;
|
||||||
|
margin-top: 1%;
|
||||||
|
font-size: xx-large;
|
||||||
|
font-weight: bold;
|
||||||
|
position: sticky;
|
||||||
|
top:0
|
||||||
|
}
|
||||||
|
|
||||||
|
.hiddable-popup-option{
|
||||||
|
flex-grow: 1;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 1.5%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-button-close{
|
||||||
|
background: padding-box;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-button-close:hover{
|
||||||
|
color: #2A93B0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hiddable-container{
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden-popup-type{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#history-request-body{
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes blur {
|
||||||
|
0% {
|
||||||
|
backdrop-filter: blur(0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
}
|
||||||
96
Frontend/assets/css/tools/mock/r11tables.css
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
.table-map {
|
||||||
|
width: 60%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-map input{
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 7px;
|
||||||
|
border: 1px solid rgba(145, 146, 146, 0.849);
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-map input.key {
|
||||||
|
background: #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modification-button.btn-add {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #00000030;
|
||||||
|
margin: auto 0 auto 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modification-button.btn-add:hover {
|
||||||
|
color:#58ac43;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modification-button.btn-hashmap {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #00000030;
|
||||||
|
margin: auto 0 auto 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modification-button.btn-hashmap:hover {
|
||||||
|
color: #ca1111;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-default {
|
||||||
|
width: 80%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-default tr {
|
||||||
|
background: #f0f0f02d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-default tr.bottom-border {
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-default th {
|
||||||
|
background: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-default tr.even {
|
||||||
|
background: #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-doc td, .table-doc th{
|
||||||
|
border-spacing: 0px;
|
||||||
|
padding: 0px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-doc td {
|
||||||
|
background-color: rgba(155, 165, 160, 0.342);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-doc th {
|
||||||
|
background-color: #3bc4f1;
|
||||||
|
text-align: left;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-default td{
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header-table tr td {
|
||||||
|
border: 1px black solid;
|
||||||
|
padding: 1.5%;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#header-table{
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-header-name{
|
||||||
|
min-width: 10vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
#historyTable, td{
|
||||||
|
padding: 1%;
|
||||||
|
overflow-x: scroll;
|
||||||
|
}
|
||||||
322
Frontend/assets/css/tools/mock/r11tool.css
Normal file
@@ -0,0 +1,322 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: "Nunito";
|
||||||
|
src: url('font/Nunito-VariableFont_wght.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hyperlink, .hyperlink:visited, .hyperlink:active {
|
||||||
|
color: rgb(47, 125, 146);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hyperlink:hover {
|
||||||
|
filter: brightness(120%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bordered-field {
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
border: 2px solid rgba(93, 99, 96, 0.705);
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 8px;
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.bordered-field:focus {
|
||||||
|
outline: none;
|
||||||
|
box-shadow: 0 0 5px rgba(81, 203, 238);
|
||||||
|
border: 2px solid #00000070;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bordered-field:disabled {
|
||||||
|
background: #eeeeeed2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertically-resizeable {
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Nunito', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: left;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool {
|
||||||
|
width: 55%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool.extended {
|
||||||
|
width: 65%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool .tool-context {
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool.extended .tool-extention {
|
||||||
|
width: 20%;
|
||||||
|
padding-top: 2%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool .tool-extention {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-extention {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-extention.active {
|
||||||
|
opacity: 100%;
|
||||||
|
pointer-events: all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clickable-text {
|
||||||
|
padding: 0;
|
||||||
|
outline: none;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
font-weight: 300;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clickable-text.highlight:hover {
|
||||||
|
color: #3bc4f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clickable-text.switch {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clickable-text.switch span.toggleIndicator:before {
|
||||||
|
content: '>';
|
||||||
|
}
|
||||||
|
|
||||||
|
.clickable-text.switch span.toggleIndicator.active:before {
|
||||||
|
content: 'v';
|
||||||
|
}
|
||||||
|
|
||||||
|
.modification-button {
|
||||||
|
padding: 0;
|
||||||
|
outline: none;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-aligned-to-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.centered-vertically {
|
||||||
|
margin-top: auto;
|
||||||
|
margin-bottom: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.display-space-between {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.display-space-evenly {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
}
|
||||||
|
|
||||||
|
.float-left {
|
||||||
|
display: flex;
|
||||||
|
justify-content: left;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-span {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: rgba(85,85,85,0.555);
|
||||||
|
}
|
||||||
|
|
||||||
|
.block-display {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block-label {
|
||||||
|
display: block;
|
||||||
|
margin: 0 0 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabmenu {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: 1px solid rgba(185, 185, 185, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabitem {
|
||||||
|
flex-grow: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabitem:hover {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabitem.active {
|
||||||
|
background: rgba(33, 34, 34, 0.705);
|
||||||
|
color: white;
|
||||||
|
font-weight: 700;
|
||||||
|
cursor:default;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.big-font {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button.active {
|
||||||
|
background: #2A93B0;
|
||||||
|
border: 1px solid #7ed0eb;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button.active:hover {
|
||||||
|
filter: brightness(110%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button {
|
||||||
|
background: #CCD1CF;
|
||||||
|
border:1px solid rgba(186, 197, 191, 0.507);
|
||||||
|
border-radius: 5px;
|
||||||
|
color: white;
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
margin: 3px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quater-width {
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.half-width {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-fourth-width {
|
||||||
|
width: 75%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.half-width.with-padding {
|
||||||
|
width: 45%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.max-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.max-width.with-padding {
|
||||||
|
width: 94%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.max-height {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.height-300 {
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.max-height.with-padding {
|
||||||
|
height: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small-margins {
|
||||||
|
margin: 3%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small-vertical-margin {
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.medium-vertical-margin {
|
||||||
|
margin-top: 30px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.large-vertical-margin {
|
||||||
|
margin-top: 50px;
|
||||||
|
margin-bottom: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textarea-300 {
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.centered-content {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.tabcontent {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabcontent.active {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hiddable {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hiddable.active {
|
||||||
|
display: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In case of collision with classes that use 'active' */
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* TODO: Add proper class */
|
||||||
|
/* textarea {
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
} */
|
||||||
|
|
||||||
|
/* TODO: Add proper class */
|
||||||
|
/* code{
|
||||||
|
line-height: 150%;
|
||||||
|
} */
|
||||||
76
Frontend/assets/css/tools/mock/r11tooltip.css
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
.tooltip-window {
|
||||||
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
|
background: #FFFFFF;
|
||||||
|
padding: 15px 30px;
|
||||||
|
font-family: 'Nunito', sans-serif;
|
||||||
|
width: 40%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-window.lite {
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Remove !important. It's bad practice and it can cause errors in future */
|
||||||
|
.section-button {
|
||||||
|
width: 100%;
|
||||||
|
padding: 15px 0;
|
||||||
|
font-size: 18px;
|
||||||
|
background: #b4b4b4c5;
|
||||||
|
cursor: pointer;
|
||||||
|
border-bottom: darkgray 2px solid !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-button:hover {
|
||||||
|
backdrop-filter: brightness(110%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-button .active {
|
||||||
|
background: #00000030;
|
||||||
|
}
|
||||||
|
|
||||||
|
.List .collapsibleContent {
|
||||||
|
border-left: #bdc5c9 2px solid;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #ffffff50;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: .section class is to generic. It should be renamed */
|
||||||
|
.section{
|
||||||
|
padding: 10px 0px 20px 0px ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: content subclass already in use. Creating content class overrides the subclass.
|
||||||
|
Make .content a subclass of .content */
|
||||||
|
/* .content {
|
||||||
|
padding: 0px 15px 0px 15px ;
|
||||||
|
text-align: justify;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: max-height .2s ease-out;
|
||||||
|
max-height: 0px;
|
||||||
|
border-left: #c0c2c3 2px solid;
|
||||||
|
|
||||||
|
} */
|
||||||
|
|
||||||
|
.collapsibleMini::before{
|
||||||
|
content: "►";
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapsibleMini.active::before{
|
||||||
|
content: "▼";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Add proper class */
|
||||||
|
/* button:hover{
|
||||||
|
filter: brightness(110%);
|
||||||
|
} */
|
||||||
@@ -1,7 +1,14 @@
|
|||||||
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;700&display=swap');
|
|
||||||
@import url('https://necolas.github.io/normalize.css/8.0.1/normalize.css');
|
@import url('https://necolas.github.io/normalize.css/8.0.1/normalize.css');
|
||||||
@import url('fontello.css');
|
@import url('fontello.css');
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Nunito";
|
||||||
|
src: url('../../fonts/Nunito-VariableFont_wght.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
.hyperlink, .hyperlink:visited, .hyperlink:active {
|
.hyperlink, .hyperlink:visited, .hyperlink:active {
|
||||||
color: rgb(47, 125, 146);
|
color: rgb(47, 125, 146);
|
||||||
@@ -15,12 +22,12 @@
|
|||||||
.tooltip-window {
|
.tooltip-window {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
right: 0;
|
right: 0;
|
||||||
filter: drop-shadow(-2px 0px 2px darkgray);
|
/* filter: drop-shadow(-2px 0px 2px black); */
|
||||||
background: #e8f3f7;
|
background: #FFFFFF;
|
||||||
padding: 15px 30px;
|
padding: 15px 30px;
|
||||||
font-family: 'Nunito', sans-serif;
|
font-family: 'Nunito', sans-serif;
|
||||||
width: 40%;
|
width: 30%;
|
||||||
height: 100%;
|
height: calc(100% - 25px);
|
||||||
overflow: scroll;
|
overflow: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,9 +38,6 @@
|
|||||||
content: "▼";
|
content: "▼";
|
||||||
} */
|
} */
|
||||||
|
|
||||||
.tooltip-window .tip {
|
|
||||||
}
|
|
||||||
|
|
||||||
.bordered-field {
|
.bordered-field {
|
||||||
border: 2px solid rgba(93, 99, 96, 0.705);
|
border: 2px solid rgba(93, 99, 96, 0.705);
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
@@ -57,13 +61,15 @@
|
|||||||
|
|
||||||
.container {
|
.container {
|
||||||
font-family: 'Nunito', sans-serif;
|
font-family: 'Nunito', sans-serif;
|
||||||
|
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: left;
|
justify-content: left;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tool {
|
.tool {
|
||||||
width: 55%;
|
width: 65%;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
}
|
}
|
||||||
@@ -255,13 +261,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.action-button.active {
|
.action-button.active {
|
||||||
background: #3bc4f1;
|
background: #2A93B0;
|
||||||
border: 1px solid #7ed0eb;
|
border: 1px solid #7ed0eb;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-button.active:hover {
|
.action-button.active:hover {
|
||||||
filter: brightness(110%);
|
filter: brightness(110%);
|
||||||
|
transition-duration: 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-button {
|
.action-button {
|
||||||
@@ -289,6 +297,10 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.half-width {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
.max-width.with-padding {
|
.max-width.with-padding {
|
||||||
width: 94%;
|
width: 94%;
|
||||||
}
|
}
|
||||||
@@ -328,6 +340,10 @@
|
|||||||
height: 300px;
|
height: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.textarea-700 {
|
||||||
|
height: 700px;
|
||||||
|
}
|
||||||
|
|
||||||
.centered-content {
|
.centered-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -390,15 +406,18 @@
|
|||||||
.section-button {
|
.section-button {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 15px 0;
|
padding: 15px 0;
|
||||||
|
margin: 5px 0px;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
background: #b4b4b4c5;
|
background: #D5D7E6;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-bottom: darkgray 2px solid !important;
|
border-bottom: darkgray 2px solid !important;
|
||||||
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-button:hover {
|
.section-button:hover {
|
||||||
/* border-bottom: #3bc4f1 2px solid; */
|
/* border-bottom: #3bc4f1 2px solid; */
|
||||||
backdrop-filter: brightness(110%);
|
backdrop-filter: brightness(100%);
|
||||||
|
transition-duration: 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-button .active {
|
.section-button .active {
|
||||||
@@ -421,12 +440,11 @@
|
|||||||
|
|
||||||
.content {
|
.content {
|
||||||
padding: 0px 15px 0px 15px ;
|
padding: 0px 15px 0px 15px ;
|
||||||
text-align: justify;
|
text-align: left;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: max-height .2s ease-out;
|
transition: max-height .2s ease-out;
|
||||||
max-height: 0px;
|
max-height: 0px;
|
||||||
border-left: #c0c2c3 2px solid;
|
border-left: #c0c2c3 2px solid;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.collapsibleMini::before{
|
.collapsibleMini::before{
|
||||||
@@ -437,10 +455,6 @@
|
|||||||
content: "▼";
|
content: "▼";
|
||||||
}
|
}
|
||||||
|
|
||||||
.content.active{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.hiddable {
|
.hiddable {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@@ -479,6 +493,28 @@ textarea {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
code{
|
code {
|
||||||
line-height: 150%;
|
line-height: 150%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 1024px) {
|
||||||
|
.rwd-hideable {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rwd-expandable {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Frontend/assets/fonts/Nunito-Italic-VariableFont_wght.ttf
Normal file
BIN
Frontend/assets/fonts/Nunito-VariableFont_wght.ttf
Normal file
BIN
Frontend/assets/images/background.jpg
Normal file
|
After Width: | Height: | Size: 291 KiB |
BIN
Frontend/assets/images/favicon.ico
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
101
Frontend/assets/images/logo_biale.svg
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
version="1.1"
|
||||||
|
id="Release11_xA0_Image_1_"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
viewBox="0 0 1010.2 146"
|
||||||
|
style="enable-background:new 0 0 1010.2 146;"
|
||||||
|
xml:space="preserve"
|
||||||
|
sodipodi:docname="logo.svg"
|
||||||
|
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||||
|
id="defs31" /><sodipodi:namedview
|
||||||
|
id="namedview29"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="1.3155811"
|
||||||
|
inkscape:cx="375.11942"
|
||||||
|
inkscape:cy="72.971558"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1135"
|
||||||
|
inkscape:window-x="1920"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="Release11_xA0_Image_1_" />
|
||||||
|
<style
|
||||||
|
type="text/css"
|
||||||
|
id="style2">
|
||||||
|
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#2A93B0;}
|
||||||
|
.st1{fill:#2A93B0;}
|
||||||
|
.st2{fill:#1A161A;}
|
||||||
|
</style>
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="M41.8,58.5L3,143.7h145.5V4.8L41.8,58.5z"
|
||||||
|
id="path4" />
|
||||||
|
<g
|
||||||
|
id="g10">
|
||||||
|
<path
|
||||||
|
class="st1"
|
||||||
|
d="M961.1,79.2h-16.9V25.3l-16.6,4.9V17.4l32-11.1h1.6V79.2z"
|
||||||
|
id="path6" />
|
||||||
|
<path
|
||||||
|
class="st1"
|
||||||
|
d="M1010.2,79.2h-16.9V25.3l-16.6,4.9V17.4l32-11.1h1.6V79.2z"
|
||||||
|
id="path8" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g26"
|
||||||
|
style="fill:#ffffff">
|
||||||
|
<path
|
||||||
|
class="st2"
|
||||||
|
d="M290.7,71.3c5-7.3,7.5-15.5,7.5-24.4c0-15-4.8-26.4-14.5-34.1C275,5.9,263,2.4,247.9,2.4h-41.6v138.1h25.5V87 l36.2,53.5h31.9l-37.5-50.9C275,86.8,284.4,80.7,290.7,71.3z M231.8,68V27.2h13.8c8,0,14.2,1.2,18.6,3.7c5.6,3.1,8.4,8.2,8.4,15.2 c0,7.5-2.2,13-6.6,16.6c-4.4,3.6-10.3,5.3-17.8,5.3H231.8z"
|
||||||
|
id="path12"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
<path
|
||||||
|
class="st2"
|
||||||
|
d="M397.5,48.4c-10.4-9.7-22.6-14.5-36.5-14.5c-16.9,0-30.6,6.4-41,19.2c-8.6,10.6-12.9,22.1-12.9,34.7v4.7 c0,13.4,5.4,25.3,16.3,35.7c10.9,10.4,24,15.6,39.2,15.6c11.5,0,21.5-3.1,30-9.2c8.5-6.2,14.6-14.1,18.3-24h-27.4 c-6.1,6.1-13.5,9.1-22.2,9.1c-6.6,0-12.5-1.8-17.8-5.4c-5.3-3.6-8.7-8.5-10.2-14.5h80.1c0.6-4.3,0.9-8.2,0.9-11.6 C414.5,72.2,408.9,59,397.5,48.4z M333.1,77.9c1.7-5.2,4.8-9.6,9.1-13.2c5.3-4.5,11.7-6.7,19.1-6.7c7.3,0,13.7,2.2,19.1,6.7 c4.5,3.7,7.6,8.1,9.3,13.2H333.1z"
|
||||||
|
id="path14"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
<rect
|
||||||
|
x="431.5"
|
||||||
|
y="2.6"
|
||||||
|
class="st2"
|
||||||
|
width="24.8"
|
||||||
|
height="137.9"
|
||||||
|
id="rect16"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
<path
|
||||||
|
class="st2"
|
||||||
|
d="M561.8,48.4c-10.4-9.7-22.6-14.5-36.5-14.5c-16.9,0-30.6,6.4-41,19.2c-8.6,10.6-12.9,22.1-12.9,34.7v4.7 c0,13.4,5.4,25.3,16.3,35.7c10.9,10.4,24,15.6,39.2,15.6c11.5,0,21.5-3.1,30-9.2c8.5-6.2,14.6-14.1,18.3-24h-27.4 c-6.1,6.1-13.5,9.1-22.2,9.1c-6.6,0-12.5-1.8-17.8-5.4c-5.3-3.6-8.7-8.5-10.2-14.5h80.1c0.6-4.3,0.9-8.2,0.9-11.6 C578.7,72.2,573.1,59,561.8,48.4z M497.3,77.9c1.7-5.2,4.8-9.6,9.1-13.2c5.3-4.5,11.7-6.7,19.1-6.7c7.3,0,13.7,2.2,19.1,6.7 c4.5,3.7,7.6,8.1,9.3,13.2H497.3z"
|
||||||
|
id="path18"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
<path
|
||||||
|
class="st2"
|
||||||
|
d="M773.6,81.7c-7-2.2-13.9-4.5-20.9-6.7c-2.5-1-4.3-2.2-5.5-3.6c-1.2-1.4-1.9-2.9-2.1-4.4c0-2.4,1-4.4,3.1-6.1 c2-1.7,4.3-2.5,6.8-2.5c2.4,0,4.4,0.6,6.2,1.8c1.8,1.2,3.2,3,4.2,5.5h23.7c0-9.2-3.4-16.8-10.3-22.7c-6.9-6-14.8-8.9-23.8-8.9 c-6.7,0-13.1,1.8-19,5.4c-11.4,7-15.5,16.8-15.7,26.7c-0.1,5,1.4,9.8,4.2,14.5c2.8,4.7,7.1,8.4,13,11.3c6.3,2.6,12.8,5.3,19.5,7.9 c6.6,2.7,10,5.8,10,9.2c0,3.2-1.2,5.9-3.4,7.9c-2.3,2.1-5.1,3.1-8.5,3.1c-2.9,0-5.5-1-7.9-3c-2.4-2-4.1-5-4.9-8.9h-25 c0,9.2,2.6,17.1,7.8,23.4c4.8,6,10.9,9.7,18.3,11.1c3.7,0.7,7.4,1.1,11,1.1c12.2,0,21.7-4.1,28.5-12.3c6-7.1,9.5-16.1,8.9-27.1 C791.2,94,784.6,86.8,773.6,81.7z"
|
||||||
|
id="path20"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
<path
|
||||||
|
class="st2"
|
||||||
|
d="M912,88.1c0-15.9-5.7-29.1-17-39.7c-10.4-9.7-22.6-14.5-36.5-14.5c-16.9,0-30.6,6.4-41,19.2 c-8.6,10.6-12.9,22.1-12.9,34.7v4.7c0,13.4,5.4,25.3,16.3,35.7c10.9,10.4,24,15.6,39.2,15.6c11.5,0,21.5-3.1,30-9.2 c8.5-6.2,14.6-14.1,18.3-24h-27.4c-6.1,6.1-13.5,9.1-22.2,9.1c-6.6,0-12.5-1.8-17.8-5.4c-5.3-3.6-8.7-8.5-10.2-14.5h80.1 C911.7,95.3,912,91.5,912,88.1z M830.6,77.9c1.7-5.2,4.8-9.6,9.1-13.2c5.3-4.5,11.7-6.7,19.1-6.7c7.3,0,13.7,2.2,19.1,6.7 c4.5,3.7,7.6,8.1,9.3,13.2H830.6z"
|
||||||
|
id="path22"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
<path
|
||||||
|
class="st2"
|
||||||
|
d="M680.5,44.4c-9.6-8-20.5-12-32.8-12c-7,0-14,1.5-21,4.5c-7,3-13.7,7.6-19.9,13.8c-5,6.2-8.6,12.2-10.7,18.2 c-2.1,6-3.2,12.2-3.2,18.8c0,15.6,5.3,28.8,15.9,39.7c10.6,10.9,23.5,16.3,38.6,16.3c12.6,0,23.7-3.9,33.2-11.8v8.5h22.3V37h-22.3 V44.4z M667.8,110.5c-5.4,5.8-12.5,8.8-21.2,8.8c-8.2,0-15.1-3-20.8-9.1s-8.5-13.3-8.5-21.8c0-4,0.7-7.9,2.2-11.6 c1.5-3.7,3.4-7.1,5.7-10.3c5.7-6.3,12.8-9.4,21.1-9.4c8.6,0,15.7,3,21.3,9c5.6,6,8.4,13.4,8.4,22.2 C675.9,97.3,673.2,104.7,667.8,110.5z"
|
||||||
|
id="path24"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 5.0 KiB |