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
|
||||
nbactions.xml
|
||||
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
|
||||
FROM maven:3.6.3-jdk-8 as target
|
||||
WORKDIR /build
|
||||
COPY pom.xml .
|
||||
COPY src/ /build/src/
|
||||
WORKDIR build
|
||||
COPY ./ ./
|
||||
RUN mvn -ntp package
|
||||
|
||||
|
||||
# Go to working directory in docker image
|
||||
# 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.s9api.XPathCompiler;
|
||||
import net.sf.saxon.s9api.XdmNode;
|
||||
|
||||
import java.util.Iterator;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Handler for saxon namespace scan engine.
|
||||
@@ -13,6 +12,7 @@ import java.util.Iterator;
|
||||
* @author Wojciech Czop
|
||||
*/
|
||||
public class NewNamespaceResolver {
|
||||
private static final Logger LOG = LogManager.getLogger("NewNamespaceResolver");
|
||||
|
||||
private NamespaceMap namespaceMap;
|
||||
|
||||
@@ -21,12 +21,13 @@ public class NewNamespaceResolver {
|
||||
* @param doc dom structure object
|
||||
* @return map of namespaces
|
||||
*/
|
||||
|
||||
// TODO: Closer inspection. Return value is never used according to IntelliJ
|
||||
//
|
||||
public NamespaceMap process(XdmNode doc) {
|
||||
namespaceMap = NamespaceMap.emptyMap();
|
||||
Iterator<XdmNode> it = doc.children().iterator();
|
||||
// TODO: remove
|
||||
while (it.hasNext()) {
|
||||
XdmNode tmp = it.next();
|
||||
for (XdmNode tmp : doc.children()) {
|
||||
extractNamespace(tmp);
|
||||
}
|
||||
// end
|
||||
@@ -38,12 +39,6 @@ public class NewNamespaceResolver {
|
||||
* @param compiler compiler used to compile xpath statements
|
||||
*/
|
||||
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()));
|
||||
}
|
||||
|
||||
@@ -58,17 +53,11 @@ public class NewNamespaceResolver {
|
||||
}
|
||||
if (node.children().iterator().hasNext()) {
|
||||
|
||||
Iterator<XdmNode> it = node.children().iterator();
|
||||
while (it.hasNext()) {
|
||||
XdmNode rNode = it.next();
|
||||
// TODO: remove
|
||||
for (XdmNode rNode : node.children()) {
|
||||
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();
|
||||
LOG.warn("Missing prefix. Parent has " + rNode.getParent().getUnderlyingNode().getPrefix() + ", but child has none");
|
||||
}
|
||||
// end
|
||||
|
||||
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 javax.xml.transform.stream.StreamSource;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
@@ -9,7 +11,7 @@ import java.io.StringWriter;
|
||||
* Handler for Saxon engine
|
||||
* @author Wojciech Czop
|
||||
*/
|
||||
public class Saxon {
|
||||
public class Saxon implements XmlEngine{
|
||||
|
||||
/**
|
||||
* Transforms string containing xml document via xslt
|
||||
@@ -18,7 +20,7 @@ public class Saxon {
|
||||
* @return transformed xml
|
||||
* @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);
|
||||
XsltCompiler compiler = processor.newXsltCompiler();
|
||||
XsltExecutable stylesheet = compiler.compile(new StreamSource(new StringReader(transform)));
|
||||
@@ -32,6 +34,11 @@ public class Saxon {
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String validate(String data, String xsd) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process xpath and return either node or wrapped atomic value
|
||||
* @param data xml to be querried
|
||||
@@ -40,7 +47,7 @@ public class Saxon {
|
||||
* @return string xml representation of the node
|
||||
* @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);
|
||||
XPathCompiler compiler = p.newXPathCompiler();
|
||||
DocumentBuilder builder = p.newDocumentBuilder();
|
||||
@@ -60,7 +67,7 @@ public class Saxon {
|
||||
sb.append(xdmItem);
|
||||
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
|
||||
* @return version of the processor
|
||||
*/
|
||||
public static String getVersion() {
|
||||
public String getVersion() {
|
||||
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.*;
|
||||
|
||||
@@ -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('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 {
|
||||
color: rgb(47, 125, 146);
|
||||
@@ -15,12 +22,12 @@
|
||||
.tooltip-window {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
filter: drop-shadow(-2px 0px 2px darkgray);
|
||||
background: #e8f3f7;
|
||||
/* filter: drop-shadow(-2px 0px 2px black); */
|
||||
background: #FFFFFF;
|
||||
padding: 15px 30px;
|
||||
font-family: 'Nunito', sans-serif;
|
||||
width: 40%;
|
||||
height: 100%;
|
||||
width: 30%;
|
||||
height: calc(100% - 25px);
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
@@ -31,9 +38,6 @@
|
||||
content: "▼";
|
||||
} */
|
||||
|
||||
.tooltip-window .tip {
|
||||
}
|
||||
|
||||
.bordered-field {
|
||||
border: 2px solid rgba(93, 99, 96, 0.705);
|
||||
border-radius: 5px;
|
||||
@@ -57,13 +61,15 @@
|
||||
|
||||
.container {
|
||||
font-family: 'Nunito', sans-serif;
|
||||
|
||||
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tool {
|
||||
width: 55%;
|
||||
width: 65%;
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
@@ -255,13 +261,15 @@
|
||||
}
|
||||
|
||||
.action-button.active {
|
||||
background: #3bc4f1;
|
||||
background: #2A93B0;
|
||||
border: 1px solid #7ed0eb;
|
||||
cursor: pointer;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.action-button.active:hover {
|
||||
filter: brightness(110%);
|
||||
transition-duration: 0.3s;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
@@ -289,6 +297,10 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.half-width {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.max-width.with-padding {
|
||||
width: 94%;
|
||||
}
|
||||
@@ -328,6 +340,10 @@
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.textarea-700 {
|
||||
height: 700px;
|
||||
}
|
||||
|
||||
.centered-content {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@@ -390,15 +406,18 @@
|
||||
.section-button {
|
||||
width: 100%;
|
||||
padding: 15px 0;
|
||||
margin: 5px 0px;
|
||||
font-size: 18px;
|
||||
background: #b4b4b4c5;
|
||||
background: #D5D7E6;
|
||||
cursor: pointer;
|
||||
border-bottom: darkgray 2px solid !important;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.section-button:hover {
|
||||
/* border-bottom: #3bc4f1 2px solid; */
|
||||
backdrop-filter: brightness(110%);
|
||||
backdrop-filter: brightness(100%);
|
||||
transition-duration: 0.3s;
|
||||
}
|
||||
|
||||
.section-button .active {
|
||||
@@ -421,12 +440,11 @@
|
||||
|
||||
.content {
|
||||
padding: 0px 15px 0px 15px ;
|
||||
text-align: justify;
|
||||
text-align: left;
|
||||
overflow: hidden;
|
||||
transition: max-height .2s ease-out;
|
||||
max-height: 0px;
|
||||
border-left: #c0c2c3 2px solid;
|
||||
|
||||
}
|
||||
|
||||
.collapsibleMini::before{
|
||||
@@ -437,10 +455,6 @@
|
||||
content: "▼";
|
||||
}
|
||||
|
||||
.content.active{
|
||||
|
||||
}
|
||||
|
||||
.hiddable {
|
||||
display: none;
|
||||
}
|
||||
@@ -482,3 +496,25 @@ textarea {
|
||||
code {
|
||||
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 |