72 Commits

Author SHA1 Message Date
f0dd41a86e finished_milestone (#279)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #279
Co-authored-by: widlam <mikolaj.widla@gmail.com>
Co-committed-by: widlam <mikolaj.widla@gmail.com>
2024-01-04 08:08:16 +01:00
971cc5f36a merge new tools (#244)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Co-authored-by: Adam Bem <bema@noreply.example.com>
Reviewed-on: #244
2023-09-05 11:15:20 +02:00
57a08c3246 Resolved merge conflict in xmlFormatter.html 2023-05-30 15:56:03 +02:00
5a331d9815 Fixed merge conflicts 2023-05-30 15:49:50 +02:00
e9221e2393 Release 11.3 2023-05-30 15:42:09 +02:00
7318708bd2 Disabled persistency in Redis (#214)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #214
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-30 15:27:15 +02:00
66b20f8256 Added tests for JSON Formatter (#212)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #212
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-30 13:17:10 +02:00
b6e6277074 Cleared unused listeners, and optimize uianimation code (#213)
Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #213
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-30 13:15:47 +02:00
fb128070dc Removed broken code 2023-05-26 14:12:11 +02:00
d0c19e19df Merged bema/ref/tools_urls to master 2023-05-26 14:11:20 +02:00
c41c3f5abc Merged widlam/refactor/issue#201 to master 2023-05-26 14:04:34 +02:00
9b18a9f42d Simplified history 2023-05-26 13:55:48 +02:00
a8d93fc2a5 Made more elegant solution to tools URLs 2023-05-26 11:57:00 +02:00
6058169818 Solved #180 and one other bug (#210)
I found and fixed bug: When in URL query was put without # at the end the page would start reloading indefinitely

Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #210
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-26 11:39:57 +02:00
d336f5d18e Fixed bug with category not bein remembered 2023-05-26 10:44:54 +02:00
45fab20cc4 Merge branch 'master' of gitea.release11.com:R11/release11-tools into widlam/refactor/issue#201 2023-05-25 14:59:43 +02:00
b733e1e344 Fixed history problem, and improve mock services frontend 2023-05-25 14:49:16 +02:00
97042faaa3 Tools can be selected through URL (solves #161) (#207)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #207
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-24 14:40:07 +02:00
8815f657e0 Clean frontend code 2023-05-24 11:08:15 +02:00
ecafb17f05 revert f9b426bb30
revert Every tool can now be accessed from URL
2023-05-24 11:06:50 +02:00
f9b426bb30 Every tool can now be accessed from URL 2023-05-24 10:33:00 +02:00
02c10b8354 Fixed not working JSON arrays (#206)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #206
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-23 13:48:22 +02:00
5b69fd1de0 Every service meant to be public work now on port 80 (#205)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #205
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-23 08:59:09 +02:00
2aaf993f7a Started to removing changing UUID and many messages system 2023-05-23 08:38:28 +02:00
d5e33381a2 Refactor of History module (#184)
Co-authored-by: widlam <mikolaj.widla@gmail.com>
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #184
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-19 13:10:45 +02:00
d231a7476b Fixed timezone (#193)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #193
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-19 13:09:01 +02:00
369256baf2 tests with variable URL (#200)
Co-authored-by: augustyd <kainytsugua.kerad@gmail.com>
Reviewed-on: #200
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Dariusz Augustyniak <augustyd@noreply.example.com>
Co-committed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-05-18 13:38:38 +02:00
e697a783ae Solved #195 and cleaned up code (#196)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #196
Reviewed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-05-18 13:36:51 +02:00
1930cde695 Postman tests (#194)
Co-authored-by: augustyd <kainytsugua.kerad@gmail.com>
Reviewed-on: #194
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Dariusz Augustyniak <augustyd@noreply.example.com>
Co-committed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-05-17 14:08:16 +02:00
bcbfd34feb Moved scripts from .html files to seperate js .files (#191)
Let's hope everything works as before or better.

Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #191
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-16 09:59:04 +02:00
2d97e39dbe Fixed 404 when no lastPage was stored (solves #189)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #190
2023-05-12 15:03:46 +02:00
c89623c3a8 Dependencies in libXML now have specified versions
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #187
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-12 14:13:47 +02:00
dc3df79fc1 Moved frontend of REST Mock to frontend container (solves #168)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #186
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-12 10:06:19 +02:00
34038a2ce9 Tools java backend now uses interfaces for engine classes (solves #167) (#179)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #179
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-11 15:23:54 +02:00
d8504ee8f8 Changed timezone (solves #164 and #181)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #183
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-11 11:20:36 +02:00
6a1c6aac46 Last opened page is now stored (solves #166) (#178)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #178
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-09 15:12:57 +02:00
72d69f2967 Froze Release11.2 (#177)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Co-authored-by: Dariusz Augustyniak <augustyd@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Reviewed-on: #177
2023-05-09 15:02:44 +02:00
7fd6fd3788 Fixed incorrect Content-Type (#174) (#175)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #175
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-09 11:15:26 +02:00
41d3b90fd8 Removed version number from Mock Service (done #172) (#173)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #173
Reviewed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-05-09 10:21:37 +02:00
c55942c24a Added syntax highlighting for XML Tools (#156)
Syntax highlight now should work on all tools apart from Mock Services.

Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #156
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-08 11:11:16 +02:00
21f5911b1c Added sample XSD schema (#163)
Due to some errors with namespaces and XSD schema simplified sample XML for that tool.

Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #163
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-08 10:13:10 +02:00
71bbe668f6 augustyd/enchancment/issue#98 (#155)
issue#98
save button when user creates new message and has unsaved data in old message

Co-authored-by: augustyd <kainytsugua.kerad@gmail.com>
Reviewed-on: #155
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Dariusz Augustyniak <augustyd@noreply.example.com>
Co-committed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-04-26 13:38:23 +02:00
4a04ac3b70 Added a email address to report a bugs (#154)
![image](/attachments/d3e81b26-ea63-4ed6-8ae6-b8945325be16)

Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #154
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-26 13:32:13 +02:00
b26840ffba Added new JSON field documentation (#153)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #153
2023-04-21 09:43:24 +02:00
1199e06bef Implemented message shown when no data type is returned. (#150)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #152
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-21 09:31:28 +02:00
1b7f6e6f70 Added META tags for SEO and SEM (#149)
Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #149
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-21 08:54:21 +02:00
fe6585d509 Merge branch 'master' of gitea.release11.com:R11/release11-tools 2023-04-19 13:36:01 +02:00
093c8756b1 Added XSLTTemplate, functions that add it to transform area and documentation for that function (#144)
Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #144
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-19 13:35:40 +02:00
2b8a9c3008 Implemented showing returned type (#112) (#148)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #148
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-19 13:33:39 +02:00
1f10a1d5b5 Resolved conflict 2023-04-19 13:31:58 +02:00
8a852b7a83 Fixed doubled category 2023-04-19 13:30:14 +02:00
38c1215889 Disabled caching for frontend (#146)
Disable caching for frontend

Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #146
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-19 13:27:52 +02:00
1fc1ab76ec Resolved another conflict 2023-04-19 13:27:49 +02:00
2f0541fe3d Resolved another conflict 2023-04-19 13:27:06 +02:00
5c39b7cfe0 Fixed error codes and added logging (#138)
fixed error codes (400 not 500) and added logging for json

Co-authored-by: augustyd <kainytsugua.kerad@gmail.com>
Reviewed-on: #138
Co-authored-by: Dariusz Augustyniak <augustyd@noreply.example.com>
Co-committed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-04-19 13:26:13 +02:00
db055ef58b Resolved another conflict 2023-04-19 13:26:10 +02:00
420bfaccd9 Resolved merge conflict in xpath.html 2023-04-19 13:18:55 +02:00
3d41447581 Added numeric functions and some string 2023-04-19 13:05:36 +02:00
a773022f0d Added tooltips for XPath 2.0 (#134)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #134
2023-04-19 13:05:36 +02:00
afcd52815f Prepared templates for new XPath tooltips (#133)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #133
2023-04-19 13:05:36 +02:00
59ffeb9363 Fixed xsd in release version (#147)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #147
Reviewed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-04-19 13:02:55 +02:00
b72157377d Disabled caching for frontend (#146)
Disable caching for frontend

Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #146
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-19 10:28:04 +02:00
0946982ab6 Added missing functions (#143)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #143
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
Reviewed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-04-18 10:55:45 +02:00
8098aeacd9 Added new tooltips for XPath 3.0 and 3.1
Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #139
Reviewed-by: Adam Bem <bema@noreply.example.com>
Reviewed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-18 10:05:44 +02:00
de94eca0ac Fixed error codes and added logging (#138)
fixed error codes (400 not 500) and added logging for json

Co-authored-by: augustyd <kainytsugua.kerad@gmail.com>
Reviewed-on: #138
Co-authored-by: Dariusz Augustyniak <augustyd@noreply.example.com>
Co-committed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-04-14 10:42:47 +02:00
a7edf934f7 Merged critical XSLT fix 2023-04-12 10:01:27 +02:00
7c0d79612a Added numeric functions and some string 2023-04-12 10:01:10 +02:00
02f1977ff0 Added tooltips for XPath 2.0 (#134)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #134
2023-04-12 10:01:10 +02:00
1816302ba1 Prepared templates for new XPath tooltips (#133)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #133
2023-04-12 10:01:10 +02:00
00f3606da6 Added numeric functions and some string 2023-04-06 14:03:39 +02:00
f77a6f15c2 Added tooltips for XPath 2.0 (#134)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #134
2023-04-06 11:53:53 +02:00
0e9a87bfe7 Prepared templates for new XPath tooltips (#133)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #133
2023-03-29 08:49:43 +02:00
232 changed files with 35312 additions and 10089 deletions

View File

@@ -1,7 +1,28 @@
from lxml import etree
from lxml import etree, html
from io import BytesIO
def convertHTML(source: str, sourceFrom: str):
htmlParser = html.HTMLParser(remove_comments=True, remove_blank_text=True)
xmlParser = etree.XMLParser(remove_comments=True, remove_blank_text=True)
if sourceFrom == "xml":
xmldoc = etree.parse(BytesIO(source.encode("utf-8")), xmlParser)
return html.tostring(xmldoc, method="html", pretty_print=True, doctype="<!DOCTYPE html>").decode()
elif sourceFrom == "html":
htmldoc = html.parse(BytesIO(source.encode("utf-8")), htmlParser)
return etree.tostring(htmldoc, method="xml", pretty_print=True, doctype="", xml_declaration=True, encoding="utf-8").decode()
else:
return
def formatHTML(source: str, prettify: bool) -> str:
parser = html.HTMLParser(remove_blank_text=True, remove_comments=True, remove_pis=True)
htmlDoc = html.parse(BytesIO(source.encode("utf-8")),parser=parser)
if not prettify:
return html.tostring(htmlDoc).decode().replace("\n", "").replace("> ", ">")
return etree.tostring(htmlDoc, encoding='unicode', pretty_print=True)
def formatXML(source: str, prettify: bool) -> str:
"""Method used to format XML
@@ -54,12 +75,12 @@ def xpath(source: str, xpath: str) -> str:
# 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)
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
return result_string, "node"
@@ -77,10 +98,12 @@ def xsd(source: str, xsd: str) -> bool:
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."
try:
xml_schema.assertValid(xml)
return "XML is valid"
except etree.DocumentInvalid as e:
return str(e)
def xslt(source: str, xslt: str) -> str:

View File

@@ -9,11 +9,11 @@ import Parser
app = Flask(__name__)
CORS(app)
cors = CORS(app, resource={
r"/*":{
"origins":"*"
}
})
# cors = CORS(app, resource={
# r"/*":{
# "origins":"*"
# }
# })
def process_xml(request: request, type: str) -> str:
"""Function to process
@@ -29,17 +29,23 @@ def process_xml(request: request, type: str) -> str:
try:
request_data = json.loads(request.get_data(as_text=True))
data = request_data['data']
process = request_data['process']
processorData = request_data['processorData']
if (type == "xsd"):
response_json['result'] = Parser.xsd(data, process)
response_json['result'] = Parser.xsd(data, processorData)
elif (type == "xslt"):
response_json['result'] = Parser.xslt(data, process)
response_json['result'] = Parser.xslt(data, processorData)
elif (type == "xpath"):
response_json['result'] = Parser.xpath(data, process)
response_json['result'], response_json['type'] = Parser.xpath(data, processorData)
elif (type == "prettify"):
response_json['result'] = Parser.formatXML(data, True)
elif (type == "minimize"):
response_json['result'] = Parser.formatXML(data, False)
elif (type == "prettifyHtml"):
response_json['result'] = Parser.formatHTML(data, True)
elif (type == "minimizeHtml"):
response_json['result'] = Parser.formatHTML(data, False)
elif (type == "convertHTML"):
response_json['result'] = Parser.convertHTML(data, processorData)
else:
raise ValueError("Valid operation types are: xsd, xslt, xpath")
@@ -54,7 +60,7 @@ def process_xml(request: request, type: str) -> str:
code = 400
finally:
exec_time = (time.time_ns() - start) / 10**6
response_json['time'] = f"{exec_time:.03f}"
response_json['duration'] = f"{exec_time:.03f}"
response_json['processor'] = "libxml2 over lxml"
return json.dumps(response_json), code
@@ -79,5 +85,17 @@ def prettify():
def minimize():
return process_xml(request, "minimize")
@app.route("/html/prettify",methods=["POST"])
def prettifyHtml():
return process_xml(request, "prettifyHtml")
@app.route("/html/minimize",methods=["POST"])
def minimizeHtml():
return process_xml(request, "minimizeHtml")
@app.route("/html/convert",methods=["POST"])
def XMLToHTMLConvertion():
return process_xml(request, "convertHTML")
if __name__ == "__main__":
app.run()

View File

@@ -1,3 +1,3 @@
lxml
flask
flask_cors
lxml==4.9.2
flask==2.3.2
flask_cors==3.0.10

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
<version>2.7.11</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
@@ -18,9 +18,10 @@
<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.3.1.Final</mapstruct.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>
@@ -57,21 +58,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.cwbase</groupId>
<artifactId>logback-redis-appender</artifactId>
<version>${logback-redis-appender.version}</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.jettison</groupId>
<artifactId>jettison</artifactId>
<version>1.4.1</version>
</dependency>
</dependencies>
<build>
@@ -101,6 +87,11 @@
<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>

View File

@@ -1,68 +0,0 @@
package com.r11.tools.config;
import java.util.Objects;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import redis.clients.jedis.JedisPool;
/**
* Class containing configuration for Redis db client
* @author Rafał Żukowicz
*/
@Configuration
@EnableRedisRepositories
@PropertySource("classpath:data-access.properties")
public class RedisConfig {
@Autowired
private Environment environment;
/**
* Bean of JedisPool - the Redis client. It stores requests in "the pool" and then fires them at Redis.
* It's considered super lightweight and fast client variant
* @return lightweight client of the Redis - the JedisPool
*/
@Bean
JedisPool jedisPool(){
final JedisPool pool = new JedisPool(environment.getProperty("redis.host"),
Integer.parseInt(environment.getProperty("redis.port")));
return pool;
}
/**
* Bean of a factory for connenction object.
* It's initialized with Redis db url property and is fed to other methods.
* @return the factory for RedisTemplates
*/
@Bean
JedisConnectionFactory jedisConnectionFactory() {
RedisStandaloneConfiguration redisStandaloneConfiguration =
new RedisStandaloneConfiguration(Objects.requireNonNull(environment.getProperty("redis.host")),
Integer.parseInt(Objects.requireNonNull(environment.getProperty("redis.port"))));
return new JedisConnectionFactory(redisStandaloneConfiguration);
}
/**
* RedisTemplate is the tool to store and retrieve given type (object) of hash from the database.
* It's like you could store your Java object by just naming it inside database. You might thing about it
* as of DAO.
* @return RedisTemplate the redis dao.
*/
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(jedisConnectionFactory());
redisTemplate.setExposeConnection(true);
redisTemplate.setDefaultSerializer(new GenericJackson2JsonRedisSerializer());
return redisTemplate;
}
}

View File

@@ -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);
}
}
);
}
}

View File

@@ -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;
}

View File

@@ -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/**");
}
}

View File

@@ -1,56 +0,0 @@
package com.r11.tools.controller;
import com.r11.tools.model.EventRequestDto;
import com.r11.tools.service.EtrackService;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.UUID;
/**
* It's the REST api for {@link com.r11.tools.model.Event}
* @author Gabriel Modzelewski
*/
@RestController
@RequestMapping(path = "/api/event")
@AllArgsConstructor
public class EventController {
private final EtrackService service;
/**
* Returns the list of Events in given time bracket.
* The list of objects is received via {@link EventRequestDto}, which contains time brackets,
* as well as the key - uuid.
* @param event EventRequestDto object that contains data needed to query the database
* @return list of {@link com.r11.tools.model.Event}
*/
@PostMapping
public ResponseEntity filterHistory(@RequestBody EventRequestDto event){
return new ResponseEntity(service.getEventsByDateTimeAndBusinessKeys(event), HttpStatus.OK);
}
/**
* Returns the list of Events of last 24h from given date.
* @param uuid unique id of message list
* @param messageId unique id of message in message list
* @return list of {@link com.r11.tools.model.Event}
*/
@GetMapping(path = "/{uuid}/{messageId}")
public ResponseEntity getLastDay(@PathVariable UUID uuid,
@PathVariable Integer messageId){
LocalDateTime requestTime = LocalDateTime.now();
LocalDateTime dayBeforeRequest = requestTime.minusDays(1L);
EventRequestDto eventRequestDto = EventRequestDto.builder()
.clientUUID(uuid)
.mockedResponseId(messageId)
.localDateTimeFrom(dayBeforeRequest)
.localDateTimeTo(requestTime)
.build();
return new ResponseEntity(service.getEventsByDateTimeAndBusinessKeys(eventRequestDto), HttpStatus.OK);
}
}

View File

@@ -1,27 +0,0 @@
package com.r11.tools.controller;
import lombok.SneakyThrows;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* Class responsible for returning homepage html
* @author Gabriel Modzelewski
*/
@Controller
@RequestMapping("/")
public class MainController {
/**
* Default path to get the homepage
* @return the view of homepage
*/
@SneakyThrows
@GetMapping
public ModelAndView showHome(){
ModelAndView mov = new ModelAndView();
mov.setViewName("html/mock");
return mov;
}
}

View File

@@ -1,46 +1,46 @@
package com.r11.tools.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.r11.tools.model.MockedMessageDto;
import com.r11.tools.service.KlausService;
import com.r11.tools.utilis.BusinessKey;
import com.r11.tools.utilis.TrackingClient;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.http.*;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.*;
import java.util.Arrays;
import java.util.Objects;
import java.util.UUID;
/**
* 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(ex.getStackTrace());
log.error(Arrays.toString(ex.getStackTrace()));
}
/**
* Updates queried message with given set of data
* @param body {@link MockedMessageDto} json representation
* @param message {@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);
public ResponseEntity<String> updateMessage(@RequestBody MockedMessageDto message){
return klausService.setMockedResponse(message);
}
@@ -48,155 +48,33 @@ public class MockController {
* 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 list of {@link MockedMessageDto}
* @return responds with 200 OK and {@link MockedMessageDto}
*/
@GetMapping({"/", "/{uuidValue}"})
public List<MockedMessageDto> getListOfMessages(@PathVariable(required = false) String 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);
List<MockedMessageDto> messages = klausService.getAllMockedResponses(clientUUID);
if(messages.size() == 0) {
klausService.setMockedResponse(buildDefaultMessage(clientUUID));
messages = klausService.getAllMockedResponses(clientUUID);
}
Collections.sort(messages);
return messages;
}
/**
* If provided UUID does not exist in database returns ResponseEntity with new generated UUID(if previous UUID is not provided),
* or old UUID(if previous UUID is provided). If provided UUID exists function returns provided UUID.
* @param givenUUIDValue the UUID client wants to check exsitance in database
* @param previousUUIDValue the previous UUID used by client(optional variable)
* @return ResponseEntity with UUID
*/
@RequestMapping(
method = RequestMethod.GET ,
path = {"/check/{givenUUIDValue}/{previousUUIDValue}",
"/check/{givenUUIDValue}"})
public ResponseEntity<String> checkUUID(
@PathVariable String givenUUIDValue
,@PathVariable(required = false) String previousUUIDValue ){
try{
UUID.fromString(givenUUIDValue);
} catch (IllegalArgumentException ex){
log.error("Wrong UUID value!");
if (previousUUIDValue == null || previousUUIDValue.equals("")){
UUID newUUID = UUID.randomUUID();
log.info("New UUID generated.");
return ResponseEntity.ok(newUUID.toString());
}
log.info("Previous UUID value restored.");
return ResponseEntity.ok(previousUUIDValue);
}
return ResponseEntity.ok(givenUUIDValue);
}
/**
* Accepts empty post request and creates new message in given set. The new message has default set of data,
* which is constructed in {@link #buildDefaultMessage(UUID, int)} method.
* @param uuidValue the key-uuid of given set of messages
* @return confirmation response with 200 OK
*/
@PostMapping("/{uuidValue}")
public ResponseEntity<String> addNewMessage(@PathVariable String uuidValue){
UUID clientUUID = UUID.fromString(uuidValue);
List<MockedMessageDto> messages = klausService.getAllMockedResponses(clientUUID);
MockedMessageDto nextMessage = buildDefaultMessage(clientUUID, findNextId(messages));
return klausService.setMockedResponse(nextMessage);
}
/**
* Deletes message of given id via client request
* @param uuidValue the key-uuid of given set of messages
* @param idValue unique id of given message
* @return after deletion the confirmation is send with status 200 OK
*/
@DeleteMapping("/{uuidValue}/{idValue}")
public ResponseEntity<String> removeMessage(@PathVariable String uuidValue,
@PathVariable String idValue){
UUID clientUUID = UUID.fromString(uuidValue);
int id = Integer.parseInt(idValue);
return klausService.deleteMockedResponse(clientUUID, id);
}
/**
* Recalls {@link #buildDefaultMessage(UUID)} for message construction and sets id of message
* @param uuid the key-uuid of given set of messages
* @param id unique id of given message
* @return message with default dataset and set id
*/
private static MockedMessageDto buildDefaultMessage(UUID uuid, int id){
MockedMessageDto message = buildDefaultMessage(uuid);
message.setMockedResponseId(id);
message = klausService.getMockedResponse(clientUUID.toString());
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 static 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());
return MockedMessageDto.builder()
.clientUUID(uuid)
.mockedResponseId(1)
.mediaType(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();
}
/**
* Finds the highest id in the list and returns it incremented by 1
* @param messages list of messages
* @return highest id incremented by 1
*/
public static int findNextId(List<MockedMessageDto> messages) {
int highestId = 0;
for (MockedMessageDto m : messages)
highestId = highestId > m.getMockedResponseId() ? highestId : m.getMockedResponseId();
return ++highestId;
}
/**
* 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 requestEntity Logs the data of request
* @param clientUUID the key-uuid of given set of messages
* @param mockedResponseId unique id of given message
* @return
*/
@GetMapping(value = "/r/{clientUUID}/{mockedResponseId}")
public ResponseEntity getMockedResponse(RequestEntity<String> requestEntity,
@PathVariable UUID clientUUID,
@PathVariable int mockedResponseId) {
TrackingClient.setBusinessKeys(Map.of(BusinessKey.INTERFACE_NAME, "getMockedResponse - request",
BusinessKey.CLIENT_UUID, String.valueOf(clientUUID),
BusinessKey.MESSAGE_ID, String.valueOf(mockedResponseId)));
// log.info(requestEntity.toString().replaceAll("\"", "\\\\\"").substring(1).replaceAll("\n",""));
TrackingClient.setBusinessKeys(Map.of(BusinessKey.INTERFACE_NAME, "getMockedResponse - response",
BusinessKey.CLIENT_UUID, String.valueOf(clientUUID),
BusinessKey.MESSAGE_ID, String.valueOf(mockedResponseId)));
MockedMessageDto mockedMessageDto = klausService.getMockedResponse(clientUUID, mockedResponseId);
@RequestMapping(value = "/r/{clientUUID}")
public ResponseEntity getMockedResponse(
@PathVariable String 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())));
}
}

View File

@@ -7,6 +7,7 @@ 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;
@@ -15,6 +16,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
* @author Rafał Żukowicz
*/
@ControllerAdvice
@CrossOrigin(origins = "*")
public class MvcExceptionHandler {
/**

View File

@@ -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);
}
}

View File

@@ -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 "";
}
}
}

View File

@@ -4,14 +4,23 @@ 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 = "compositePrimaryKey", expression = "java(mockedMessageDto.getClientUUID() + \"_\"" +
" + mockedMessageDto.getMockedResponseId())")
@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);
}
}

View File

@@ -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);
}

View File

@@ -1,36 +0,0 @@
package com.r11.tools.model;
import java.time.LocalDateTime;
import lombok.*;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.lang.Nullable;
/**
* Pojo class for Event entity
* @author Rafał Żukowicz
*/
@Data
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Event implements Comparable<Event>{
@DateTimeFormat(pattern = "yyyy-MM-ddTHH:mm:ss")
private LocalDateTime dateTimeStamp;
@Nullable
private String interfaceName;
@Nullable
private String clientUUID;
@Nullable
private Integer messageId;
private String thread;
private String level;
@Nullable
private String message;
@Override
public int compareTo(Event o) {
return this.getDateTimeStamp().compareTo(o.getDateTimeStamp()) * -1;
}
}

View File

@@ -1,10 +1,6 @@
package com.r11.tools.model;
import com.r11.tools.model.constraints.HttpCode;
import java.io.Serializable;
import java.util.Map;
import java.util.UUID;
import javax.validation.constraints.Positive;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -13,6 +9,11 @@ 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
@@ -23,18 +24,14 @@ import org.springframework.data.redis.core.index.Indexed;
@NoArgsConstructor
@AllArgsConstructor
public class MockedMessage implements Serializable {
@Id
private String compositePrimaryKey;
@Indexed
private UUID clientUUID;
@Positive
private Integer mockedResponseId;
private String mediaType;
@Id
private String clientUUID;
private String contentType;
private String messageBody;
private Map<String, String> httpHeaders;
@HttpCode
private Integer httpStatus;
private LocalDateTime createdAt;
}

View File

@@ -1,12 +1,11 @@
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;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
import lombok.*;
/**
* Alternative version of {@link MockedMessage} used in http body
@@ -18,19 +17,12 @@ import lombok.*;
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class MockedMessageDto implements Serializable, Comparable<MockedMessageDto> {
private UUID clientUUID;
@NotNull
@Positive
private Integer mockedResponseId;
private String mediaType;
public class MockedMessageDto implements Serializable{
private String clientUUID;
private String contentType;
private String messageBody;
private Map<String, String> httpHeaders;
@HttpCode
private Integer httpStatus;
@Override
public int compareTo(MockedMessageDto message) {
return this.mockedResponseId > message.getMockedResponseId() ? 1 : -1;
}
}

View File

@@ -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;
}
}

View File

@@ -1,28 +1,32 @@
package com.r11.tools.model;
import java.time.LocalDateTime;
import java.util.UUID;
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 Event} list
* 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 EventRequestDto {
public class RequestHistoryDTO {
private UUID clientUUID;
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private LocalDateTime localDateTimeFrom;
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private LocalDateTime localDateTimeTo;
private Integer mockedResponseId;
private LocalDateTime dateTimeStamp;
private Map<String,String> headers;
private HttpMethod httpMethod;
private String requestBody;
}

View File

@@ -1,20 +0,0 @@
package com.r11.tools.repository;
import com.r11.tools.model.Event;
import com.r11.tools.utilis.BusinessKey;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
/**
* Event entity dao interface
* @author Rafał Żukowicz
*/
@Repository
@Transactional
public interface EventRepository {
List<Event> findEvents(LocalDateTime localDateTimeFrom, LocalDateTime localDateTimeTo,
Map<BusinessKey, String> businessKeys);
}

View File

@@ -1,99 +0,0 @@
package com.r11.tools.repository;
import static com.r11.tools.utilis.RedisAppender.LOG_PREFIX;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.r11.tools.model.Event;
import com.r11.tools.utilis.BusinessKey;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Repository;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
/**
* Builds Event list based on logs created via {@link com.r11.tools.utilis.TrackingClient} and {@link com.r11.tools.utilis.RedisAppender}
* @author Rafał Żukowicz
*/
@Repository
@AllArgsConstructor
public class EventRepositoryImpl implements EventRepository {
private final JedisPool jedisPool;
private final ObjectMapper objectMapper;
/**
* Creates list of {@link Event} based on {@link com.r11.tools.model.EventRequestDto} data via searching logs
* @param localDateTimeFrom date from which logs are retrieved
* @param localDateTimeTo date to which logs are retrieved
* @param businessKeys set keys for redis values
* @return
*/
@Override
public List<Event> findEvents(LocalDateTime localDateTimeFrom, LocalDateTime localDateTimeTo,
Map<BusinessKey, String> businessKeys) {
List<String> eventStrings = findEventsBetweenDates(localDateTimeFrom.toLocalDate(), localDateTimeTo.toLocalDate());
if (businessKeys.size() > 0) {
eventStrings = businessKeysFilter(eventStrings, businessKeys);
}
List<Event> events = parseEvents(eventStrings);
if (localDateTimeFrom.toLocalTime() != LocalTime.MIN) {
events = events.stream().filter(event -> event.getDateTimeStamp().compareTo(localDateTimeFrom) >= 0)
.collect(Collectors.toList());
}
return events.stream().filter(event -> event.getDateTimeStamp().compareTo(localDateTimeTo) <= 0)
.collect(Collectors.toList());
}
/**
* Returns logs between given dates
* @param localDateFrom date from which logs are retrieved
* @param localDateTo date to which logs are retrieved
* @return
*/
private List<String> findEventsBetweenDates(LocalDate localDateFrom, LocalDate localDateTo) {
try (Jedis jedis = jedisPool.getResource()) {
return localDateFrom.datesUntil(localDateTo.plusDays(1)).map(day -> LOG_PREFIX + day.toString())
.map(key -> jedis.lrange(key, 0, -1)).flatMap(Collection::stream).collect(Collectors.toList());
}
}
/**
* Filters keys so only the ones queried are retirned
* @param events list of logs
* @param businessKeys set keys for redis values
* @return filtered list of logs
*/
private List<String> businessKeysFilter(List<String> events, Map<BusinessKey, String> businessKeys) {
for (Map.Entry<BusinessKey, String> entry : businessKeys.entrySet()) {
String stringPattern = entry.getKey().getReasonPhrase()+ "\"" + ":" + "\"" + entry.getValue() + "\"";
events = events.stream().filter(s -> s.contains(stringPattern)).collect(Collectors.toList());
}
return events;
}
/**
* Parses list of logs into list of {@link Event}
* @param eventStrings list of logs
* @return list of {@link Event}
*/
private List<Event> parseEvents(List<String> eventStrings) {
List<Event> events = new ArrayList<>();
for (String eventString : eventStrings) {
eventString = eventString.replaceAll("\\R", "");
try {
events.add(objectMapper.readValue(eventString, Event.class));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
return events;
}
}

View File

@@ -1,24 +1,16 @@
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;
import java.util.Optional;
/**
* 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, String> {
/**
* 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<List<MockedMessage>> findAllByClientUUID(UUID clientUUID);
}
public interface MockedResponseRepository extends CrudRepository<MockedMessage, String> {}

View File

@@ -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);
}

View File

@@ -1,20 +0,0 @@
package com.r11.tools.service;
import com.r11.tools.model.Event;
import com.r11.tools.model.EventRequestDto;
import java.util.List;
import org.springframework.stereotype.Service;
/**
* Spring service interface for {@link com.r11.tools.controller.EventController}
* @author Rafał Żukowicz
*/
@Service
public interface EtrackService {
/**
* Searches for {@link Event} objects between date brackets
* @param eventsDto object containing required data for request
* @return list of {@link Event}
*/
List<Event> getEventsByDateTimeAndBusinessKeys(EventRequestDto eventsDto);
}

View File

@@ -1,44 +0,0 @@
package com.r11.tools.service;
import com.r11.tools.model.Event;
import com.r11.tools.model.EventRequestDto;
import com.r11.tools.repository.EventRepository;
import com.r11.tools.utilis.BusinessKey;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Spring Service for {@link com.r11.tools.controller.EventController}. Contains logic required for quering
* the database for {@link Event} objects
* @author Rafał Żukowicz
*/
@Service
@AllArgsConstructor
public class EtrackServiceImpl implements EtrackService {
private final EventRepository eventRepository;
/**
* Adds {@link BusinessKey} to {@link EventRequestDto}
* in order to create query via{@link com.r11.tools.repository.EventRepositoryImpl}
* @param eventsDto object containing required data for request
* @return list of {@link Event}
*/
@Override
public List<Event> getEventsByDateTimeAndBusinessKeys(EventRequestDto eventsDto) {
Map<BusinessKey, String> businessKeys = new HashMap<>();
businessKeys.put(BusinessKey.CLIENT_UUID, eventsDto.getClientUUID().toString());
if (eventsDto.getMockedResponseId() != null){
businessKeys.put(BusinessKey.MESSAGE_ID, String.valueOf(eventsDto.getMockedResponseId()));
}
List<Event> events = eventRepository.findEvents(eventsDto.getLocalDateTimeFrom(), eventsDto.getLocalDateTimeTo(),
businessKeys);
Collections.sort(events);
return events;
}
}

View File

@@ -1,7 +1,8 @@
package com.r11.tools.service;
import com.r11.tools.model.MockedMessageDto;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
@@ -12,8 +13,6 @@ import org.springframework.stereotype.Service;
*/
@Service
public interface KlausService {
ResponseEntity<String> deleteMockedResponse(UUID clientUUID, int mockedResponseId);
List<MockedMessageDto> getAllMockedResponses(UUID clientUUID);
MockedMessageDto getMockedResponse(UUID clientUUID, int mockedResponseId);
MockedMessageDto getMockedResponse(String clientUUID);
ResponseEntity<String> setMockedResponse(MockedMessageDto mockedMessageDto);
}

View File

@@ -1,6 +1,5 @@
package com.r11.tools.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.r11.tools.mappers.MockedMessageMapper;
import com.r11.tools.model.MockedMessage;
import com.r11.tools.model.MockedMessageDto;
@@ -11,18 +10,21 @@ 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.stereotype.Service;
import java.util.List;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* 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
@@ -30,59 +32,53 @@ public class KlausServiceImpl implements KlausService {
private final MockedMessageMapper mockedMessageMapper;
private final Logger log = LogManager.getRootLogger();
private final MockedResponseRepository mockedResponseRepository;
private final ObjectMapper objectMapper;
/**
* Removes message of given id in given key-uuid set
* @param clientUUID the key-uuid of given set of messages
* @param mockedResponseId unique id of given message
* @return confirmation and status 200 OK
*/
@Override
public ResponseEntity<String> deleteMockedResponse(UUID clientUUID, int mockedResponseId) {
String key = clientUUID.toString() + "_" + mockedResponseId;
mockedResponseRepository.deleteById(key);
log.info("Message: "+mockedResponseId+" has been removed.");
return new ResponseEntity<>("MockedResponse has been removed successfully",
new HttpHeaders(), HttpStatus.ACCEPTED);
}
/**
* Returns all messages of given key-uuid
* @param clientUUID the key-uuid of given set of messages
* @return List of {@link MockedMessageDto}
*/
@Override
public List<MockedMessageDto> getAllMockedResponses(UUID clientUUID){
Optional<List<MockedMessage>> listOptional = mockedResponseRepository.findAllByClientUUID(clientUUID);
log.info("Messages for UUID: "+clientUUID+" has been fetched from DB.");
return listOptional.map(mockedMessages -> mockedMessages.stream()
.map(mockedMessageMapper::mockedMessageToMockedMessageDto)
.collect(Collectors.toList())).orElse(List.of());
}
/**
* 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
* @param mockedResponseId unique id of given message
* @return {@link MockedMessageDto} object
*/
@SneakyThrows
@Override
public MockedMessageDto getMockedResponse(UUID clientUUID, int mockedResponseId){
String key = clientUUID.toString() + "_" + mockedResponseId;
Optional<MockedMessage> optionalMockedMessage = mockedResponseRepository.findById(key);
MockedMessageDto mockedMessageDto = MockedMessageDto.builder()
.clientUUID(clientUUID)
.mockedResponseId(mockedResponseId)
.build();
public MockedMessageDto getMockedResponse(String clientUUID){
Optional<MockedMessage> optionalMockedMessage = mockedResponseRepository.findById(clientUUID);
MockedMessageDto mockedMessageDto;
if (optionalMockedMessage.isPresent()) {
mockedMessageDto = mockedMessageMapper.mockedMessageToMockedMessageDto(optionalMockedMessage.get());
//log.info(mockedMessageDto.toString().replaceAll("\"", "\\\\\""));
return mockedMessageDto;
} else {
MockedMessageDto defaultMessage = buildDefaultMessage(clientUUID);
setMockedResponse(defaultMessage);
return defaultMessage;
}
//log.info(mockedMessageDto.toString().replaceAll("\"", "\\\\\""));
return mockedMessageDto;
}
/**
* 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(String uuid){
Map<String, String> headers = new HashMap<>();
headers.put("Keep-Alive", "timeout=60");
headers.put("Connection", "keep-alive");
headers.put("Date", LocalDateTime.now().toString());
return 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();
}
/**
@@ -93,8 +89,10 @@ public class KlausServiceImpl implements KlausService {
@SneakyThrows
@Override
public ResponseEntity<String> setMockedResponse(MockedMessageDto mockedMessageDto) {
mockedResponseRepository.save(mockedMessageMapper.mockedMessageDtoToMockedMessage(mockedMessageDto));
//log.info(mockedMessageDto.toString().replaceAll("\"", "\\\\\""));
MockedMessage message = mockedMessageMapper.mockedMessageDtoToMockedMessage(mockedMessageDto);
message.setCreatedAt(LocalDateTime.now());
log.info("SAVE:"+message.toString().replace("\n"," "));
mockedResponseRepository.save(message);
return new ResponseEntity<>("MockedResponse has been setup successfully!", new HttpHeaders(),
HttpStatus.ACCEPTED);
}

View File

@@ -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);
}

View File

@@ -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));
}
}

View File

@@ -1,24 +0,0 @@
package com.r11.tools.utilis;
import lombok.AllArgsConstructor;
/**
* Enum of keys for redis database.
* @author Rafał Żukowicz
*/
@AllArgsConstructor
public enum BusinessKey {
INTERFACE_NAME("interfaceName"),
CLIENT_UUID("clientUUID"),
MESSAGE_ID("messageId");
private final String phrase;
/**
* Returns string value of given enum variant
* @return string value of enum
*/
public String getReasonPhrase() {
return this.phrase;
}
}

View File

@@ -1,235 +0,0 @@
package com.r11.tools.utilis;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Layout;
import ch.qos.logback.core.UnsynchronizedAppenderBase;
import com.cwbase.logback.AdditionalField;
import com.cwbase.logback.JSONEventLayout;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.Iterator;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Protocol;
/**
* Class is used to insert logs directly to Redis. {@link com.release11.klaus.repository.EventRepositoryImpl} is using those logs.
* @author Rafał Żukowicz
* @author Gabriel Modzelewski
*/
public class RedisAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {
JedisPool pool;
JSONEventLayout jsonlayout;
Layout<ILoggingEvent> layout;
String host = "localhost";
int port = Protocol.DEFAULT_PORT;
String key = null;
int timeout = Protocol.DEFAULT_TIMEOUT;
String password = null;
int database = Protocol.DEFAULT_DATABASE;
public static final String LOG_PREFIX = "logstash_";
public RedisAppender() {
jsonlayout = new JSONEventLayout();
}
/**
* Appends JedisPool by another log
* @param event object containing log info
*/
@Override
protected void append(ILoggingEvent event) {
Jedis client = pool.getResource();
try {
String json = layout == null ? jsonlayout.doLayout(event) : layout.doLayout(event);
key = LOG_PREFIX + LocalDate.now();
client.rpush(key, json);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (client != null) {
client.close();
}
}
}
@Deprecated
public String getSource() {
return jsonlayout.getSource();
}
@Deprecated
public void setSource(String source) {
jsonlayout.setSource(source);
}
@Deprecated
public String getSourceHost() {
return jsonlayout.getSourceHost();
}
@Deprecated
public void setSourceHost(String sourceHost) {
jsonlayout.setSourceHost(sourceHost);
}
@Deprecated
public String getSourcePath() {
return jsonlayout.getSourcePath();
}
@Deprecated
public void setSourcePath(String sourcePath) {
jsonlayout.setSourcePath(sourcePath);
}
@Deprecated
public String getTags() {
if (jsonlayout.getTags() != null) {
Iterator<String> i = jsonlayout.getTags().iterator();
StringBuilder sb = new StringBuilder();
while (i.hasNext()) {
sb.append(i.next());
if (i.hasNext()) {
sb.append(',');
}
}
return sb.toString();
}
return null;
}
@Deprecated
public void setTags(String tags) {
if (tags != null) {
String[] atags = tags.split(",");
jsonlayout.setTags(Arrays.asList(atags));
}
}
@Deprecated
public String getType() {
return jsonlayout.getType();
}
@Deprecated
public void setType(String type) {
jsonlayout.setType(type);
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public int getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getDatabase() {
return database;
}
public void setDatabase(int database) {
this.database = database;
}
@Deprecated
public void setMdc(boolean flag) {
jsonlayout.setProperties(flag);
}
@Deprecated
public boolean getMdc() {
return jsonlayout.getProperties();
}
@Deprecated
public void setLocation(boolean flag) {
jsonlayout.setLocationInfo(flag);
}
@Deprecated
public boolean getLocation() {
return jsonlayout.getLocationInfo();
}
@Deprecated
public void setCallerStackIndex(int index) {
jsonlayout.setCallerStackIdx(index);
}
@Deprecated
public int getCallerStackIndex() {
return jsonlayout.getCallerStackIdx();
}
@Deprecated
public void addAdditionalField(AdditionalField p) {
jsonlayout.addAdditionalField(p);
}
public Layout<ILoggingEvent> getLayout() {
return layout;
}
public void setLayout(Layout<ILoggingEvent> layout) {
this.layout = layout;
}
/**
* Starts new instance of JedisPool
*/
@Override
public void start() {
super.start();
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setTestOnBorrow(true);
pool = new JedisPool(config, host, port, timeout, password, database);
}
/**
* Stops and destroys JedisPool object
*/
@Override
public void stop() {
super.stop();
pool.destroy();
}
}

View File

@@ -1,24 +0,0 @@
package com.r11.tools.utilis;
import java.util.Map;
import org.slf4j.MDC;
/**
* This static class has one purpose and one purpose only. It logs data about incomming requests.
* The data from logs is received via {@link com.release11.klaus.repository.EventRepositoryImpl}
* @author Rafał Żukowski
*/
public final class TrackingClient {
/**
* Logs data inside the given map
* @param businessKeysMap map containing all the information about incomming request
*/
public static void setBusinessKeys(Map<BusinessKey, String> businessKeysMap){
for (Map.Entry<BusinessKey, String> entry : businessKeysMap.entrySet()) {
MDC.put(entry.getKey().getReasonPhrase(), entry.getValue());
}
}
}

View File

@@ -5,3 +5,12 @@ 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=1440
retention.minutes-to-delete-history-record=1440
retention.retention-cooldown=1440

View File

@@ -1,2 +0,0 @@
redis.host = redis
redis.port = 6379

View File

@@ -2,25 +2,8 @@
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<property name="HOME_LOG" value="/log/mockServices.log"/>
<!--https://github.com/kmtong/logback-redis-appender-->
<appender name="LOGSTASH" class="com.r11.tools.utilis.RedisAppender">
<host>redis</host>
<port>6379</port>
<key>logstash</key>
<layout class="ch.qos.logback.classic.PatternLayout">
<!--https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html-->
<Pattern>
{"dateTimeStamp" : "%d{yyyy-MM-dd}T%d{HH:mm:ss}", "eventId":"%X{eventId}", "interfaceName":"%X{interfaceName}", "clientUUID":"%X{clientUUID}", "messageId":"%X{messageId}", "thread":"%t","level":"%-5level", "message":"%msg"}%n
</Pattern>
</layout>
</appender>
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="LOGSTASH" />
</appender>
<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>
@@ -34,7 +17,6 @@
</appender>
<root level="DEBUG">
<appender-ref ref="ASYNC" />
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>

View File

@@ -1,32 +0,0 @@
@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');
@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;
}

View File

@@ -1,14 +0,0 @@
<?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="&#xe801;" 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="&#xe802;" 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>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,59 +0,0 @@
@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'; } /* '' */

View File

@@ -1,4 +0,0 @@
.overflowedTableContent {
max-height: 750px;
overflow: scroll;
}

View File

@@ -1,72 +0,0 @@
.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;
}

View File

@@ -1,57 +0,0 @@
#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;
}

View File

@@ -1,104 +0,0 @@
#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;
}

View File

@@ -1,71 +0,0 @@
.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;
}

View File

@@ -1,325 +0,0 @@
@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;
}
.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-context {
width: 75%;
}
.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%;
} */

View File

@@ -1,76 +0,0 @@
.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%);
} */

View File

@@ -1,324 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>R11 MockedServices</title>
<meta charset="utf-8">
<link rel="stylesheet" href="../css/fontello.css" type="text/css">
<link rel="stylesheet" href="../css/main.css" type="text/css">
<!-- <link rel="stylesheet" href="css/common.css" type="text/css"> -->
<link rel="stylesheet" href="../css/common.css" type="text/css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<!-- <script src="../js/dyn_host.js"></script> -->
</head>
<body>
<div class="container">
<div class="tool extended">
<div class="tool-context">
<div>
<h1>MockedServices <span class="version-span">v1.0.0</span></h1>
</div>
<div>
<label for="uuid-input" class="block-display">UUID</label>
<div id="uuid-edit">
<div id="uuid-edit-field" class="bordered-field disabled">
<input id="uuid-input" disabled onfocusout="changeUUID(this);" value="UUID" />
<button onclick="copyUUIDToClipboard();" class="uuid-inputField-icon modification-button flex-item btn-copy action-button">
<span class="material-icons uuid-inputField-icon-span ">content_copy</span>
</button>
</div>
<div id="editableBlock">
<input type="checkbox" onchange="changeEditionOfUUID(this)" name="editable" id="editable" value="false"/>
<label for="editable">Editable</label>
</div>
</div>
<div class="hiddable" id="uuid-validation-strategy">
<label><b>UUID generation strategy:</b></label>
<input type="radio" checked name="uuid-validation-type" value="new" id="generateNew"/>
<label for="generateNew">Generate new UUID</label>
<input type="radio" name="uuid-validation-type" value="restore" id="restore"/>
<label for="restore">Restore previous UUID</label>
</div>
</div>
<div>
<!-- h2 -->
<div id="basicItemData" class="hiddable active"><h2>Your Message</h2></div>
<div id="advancedItemData" class="hiddable"><h2>Messaged id: <span id="mockedMessageId">1</span></h2></div>
<!-- link -->
<div>
<label for="messageLink" class="block-display">Link</label>
<div id="messageLink" class="bordered-field max-width with-padding disabled-background"><a class="hyperlink" href="www.google.com" target="_blank">www.google.com</a></div>
<!-- <input id="messageLink" disabled class="bordered-field max-width with-padding" value="http://yourlink.com/r/api/mock/blablabla"> -->
</div>
<div class="display-space-between max-width">
<!-- status and type -->
<div class="medium-input block-display small-vertical-margin">
<!-- status -->
<div class="max-width small-vertical-margin">
<label for="httpStatus">Http Status</label>
<input id="httpStatus" type="number" class="bordered-field max-width data-field" value="200" list="httpStatusSuggestion"/>
<datalist id="httpStatusSuggestion">
<option value="200">
<option value="300">
<option value="400">
<option value="403">
<option value="404">
<option value="500">
</datalist>
</div>
<!-- content type -->
<div class="max-width small-vertical-margin">
<label for="typeSelector">Content Type</label>
<input id="typeSelector" class="bordered-field max-width data-field" type="text" value="application/xml" list="contentTypes">
<datalist id="contentTypes">
<option value="application/xml">
<option value="application/json">
<option value="text/xml">
</datalist>
</div>
</div>
<div id="btnSave" class="small-margins half-width with-padding action-button" style="background-color: white; border: 0px;">
<button id="btn-save" class="small-margins half-width with-padding action-button" style="width: 100%; height: 100%;">Save</button>
</div>
</div>
<!-- body -->
<div class="small-vertical-margin">
<label for="bodyEditor">Body</label>
<textarea id="bodyEditor" class="data-field bordered-field max-width with-padding height-300 vertically-resizeable"></textarea>
</div>
<!-- show/hide -->
<button id="optional" class="clickable-text highlight switch"><span class="toggleIndicator"></span> show/hide advanced settings</button>
<!-- advanced -->
<div id="advanced" class="max-width with-padding hiddable">
<!-- tab menu -->
<div class="tabmenu medium-vertical-margin">
<button id="headersTab" class="tabitem active clickable-text big-font">Headers</button>
<button id="historyTab" class="tabitem clickable-text big-font">History</button>
</div>
<!-- container -->
<div class="medium-vertical-margin">
<!-- headers -->
<div id="headers" class="medium-vertical-margin tabcontent active">
<table class="table-map">
<thead>
<tr>
<th>Name</th>
<th>Value</th>
<th></th>
</tr>
</thead>
<tbody id="headerMapTable">
<tr>
<td><input class="key" value="basic value"></td>
<td><input value="basic value"></td>
<td><button class="modification-button btn-hashmap"><i class="icon-cancel"></i></button></td>
</tr>
</tbody>
<tr>
<td><input id="headerKeyInput" placeholder="name"></td>
<td><input id="headerValueInput" placeholder="value"></td>
<td><button id="btn-newRow" class="modification-button btn-add"><i class="icon-plus"></i></button></td>
</tr>
</table>
</div>
<!-- history -->
<div id="history" class="medium-vertical-margin tabcontent">
<div class="block-display max-width">
<button id="btn-history-filter" class="clickable-text highlight switch"><span class="toggleIndicator"></span> filter</button>
<div id ="history-filter" class="display-space-between max-width small-vertical-margin hiddable">
<div class="three-fourth-width display-space-evenly">
<div class="block-display half-width with-padding">
<label for="historyFrom" class="block-label">From</label>
<input id="historyFrom" type="date" class="bordered-field max-width with-padding">
<input id="historyTimeFrom" type="time" class="small-vertical-margin bordered-field max-width with-padding">
</div>
<div class="block-display half-width with-padding">
<label for="historyTo" class="block-label">To</label>
<input id="historyTo" type="date" class="bordered-field max-width with-padding">
<input id="historyTimeTo" type="time" class="small-vertical-margin bordered-field max-width with-padding">
</div>
</div>
<button id="btn-searchHistory" class="quater-width action-button active small-margins">Search</button>
</div>
<div class="max-width centered-content large-vertical-margin overflowedTableContent">
<table id="historyTable" class="table-default">
<thead>
<tr class="bottom-border">
<th>Timestamp</th>
<th>Type</th>
</tr>
</thead>
<tbody>
<!-- <tr class="even">
<td>2021-01-01T10:57:26</td>
<td>Client request</td>
</tr>
<tr>
<td>2021-01-01T10:57:26</td>
<td>Client request</td>
</tr> -->
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="selectMenuContent" class="tool-extention">
<!-- header -->
<div>
<h2>Message List</h2>
</div>
<!-- tile list -->
<div id="listItems">
<!-- <div class="tile">
<div class="content">
<div class="display-space-between">
<div class="centered-vertically">
<p>Id: 2</p>
<p>Status: 200</p>
</div>
<div>
<button id="test1" class="modification-button btn-tile"><i class="icon-cancel"></i></button>
</div>
</div>
</div>
</div> -->
</div>
<div id="new-tile" class="max-width centered-content small-vertical-margin">
<button id="btn-newtile" class="modification-button btn-addtile"><i class="icon-plus"></i></button>
</div>
</div>
</div>
<div class="tooltip-window lite">
<div>
<h2>What's this?</h2>
<p>MockedServices is a tool that allows developer to create, in easy and simple way, http server mocked endpoints for integration tests.</p>
<h2>Help</h2>
<p>When cursor hovers over an item. It's description is displayed below.</p>
<div class="large-vertical-margin">
<div id="messageLinkTip" class="tip">
<h3>Link</h3>
<p>Link is an url representing an endpoint at which you can receive your mocked response by simply sending get request.</p>
</div>
</div>
<div class="large-vertical-margin">
<div id="btnSaveTip" class="tip">
<h3>Save button!</h3>
<p>To save message, the message must be changed!</p>
</div>
</div>
<div class="large-vertical-margin">
<div id="btn-newTileTip" class="tip">
<h3>Add new message</h3>
<p>This button adds new message.</p>
</div>
</div>
<div class="large-vertical-margin">
<div id="UUIDFieldTip" class="tip">
<h3>UUID</h3>
<p>UUID is an Unique ID that represents you in API. By UUID your messages is saved in database. You can change it to access your previous configuration of mocked messages</p>
</div>
</div>
<div class="large-vertical-margin">
<div id="UUIDValidationStrategyTip" class="tip">
<h3>UUID Checking Strategy</h3>
<p>When you provide invalid UUID you can choose what do with it. You can generate new UUID or restore previous.</p>
</div>
</div>
<div class="large-vertical-margin">
<div id="UUIDEditionTip" class="tip">
<h3>UUID Edition</h3>
<p>Unlocks you ability to edit UUID</p>
</div>
</div>
<div class="large-vertical-margin">
<div id="messagesTip" class="tip">
<h3>Message</h3>
<p>This is saved messages, with unique id.</p>
</div>
</div>
<div class="large-vertical-margin">
<div id="httpStatusTip" class="tip">
<h3>Http Status</h3>
<p>Value of the field is corresponding to status value that server will return.</p>
</div>
</div>
<div class="large-vertical-margin">
<div id="typeSelectorTip" class="tip">
<h3>Content Type</h3>
<p>Value of the field describes content of body payload contained in the response. For example if content is in xml format the value should be "application/xml" or "text/xml"</p>
</div>
</div>
<div class="large-vertical-margin">
<div id="bodyEditorTip" class="tip">
<h3>Body</h3>
<p>Value of the field describes content of response body. It's basicly the message we want server to return. If it's simple response like 200 OK or 404 not found then field might be left empty.</p>
</div>
</div>
<div class="large-vertical-margin">
<div id="headersTabTip" class="tip">
<h3>Headers</h3>
<p>Content of this tab allows to set and modify headers that will be included in the response.</p>
</div>
</div>
<div class="large-vertical-margin">
<div id="historyTabTip" class="tip">
<h3>History</h3>
<p>Content of this tab displays the history of requests or responses received/sent to the endpoint</p>
</div>
</div>
<div class="large-vertical-margin">
<div id="newHeaderTip" class="tip">
<h3>New header</h3>
<p>Insert value in the field and press the plus icon to add a new header to the message.</p>
</div>
</div>
</div>
</div>
</div>
<div id="overlay"></div>
<div id="modal-uuidChanged" class="modal">
<div class="header">
<div>Change UUID info<i class="r-exclamation"></i></div>
<button onclick="window.location.reload();">&times;</button>
</div>
<div id="changeUUIDSuccess" class="body hiddable uuid-modal-body">Your message UUID has been changed successfully.</div>
<div id="newUUID" class="body hiddable uuid-modal-body">You provided wrong UUID! <br> New UUID has been generated!</div>
<div id="restoredUUID" class="body hiddable uuid-modal-body">You provided wrong UUID! <br> Old UUID has been restored!</div>
<div id="noChgUUID" class="body hiddable uuid-modal-body">You doesn't provide any change to UUID!</div>
</div>
<div id="modal-confirm" class="modal">
<div class="header">
<div>Message saved<i class="r-exclamation"></i></div>
<button>&times;</button>
</div>
<div class="body">Your message has been successfuly saved.<br>You might view it under the link.</div>
</div>
<div id="modal-query" class="modal">
<div class="header">
<div>Unsaved data<i class="r-exclamation"></i></div>
<button>&times;</button>
</div>
<div class="body">You haven't saved your message! Any changes will be lost.<br>Do you want to continue?</div>
<div class="function">
<button>Yes</button>
<button>No</button>
</div>
</div>
<script type="text/javascript" src="../js/modal.js"></script>
<script type="text/javascript" src="../js/uianimation.js"></script>
<script type="text/javascript" src="../js/datatransfer.js"></script>
<script type="text/javascript" src="../js/historyloader.js"></script>
<script type="text/javascript" src="../js/fiddle.js"></script>
</body>
</html>

View File

@@ -1,540 +0,0 @@
var clientUUID = '';
var advancedDisplayed = false;
var json = {};
var jsonIndex = 0;
var lastId = 1;
var htable_row = 0;
var host = getDomain();
var dataModified = false;
const addMessageName = 'addMessage';
const loadMessageName = 'changeMessage';
const removeMessageName = 'removeMessage';
const C_UUID = 'mock-uuid';
const C_ID = 'last-displayed-id';
const C_ADV = 'advanced-mode';
const color_red = "#ff8f8f";
const color_grey = "#6b6b6b";
const setModified = function(){
setDataModified();
}
const setOrigin = function(){
setDataOrigin();
}
const getUpdate = function(){
updateData();
}
const dataRefresh = function(){
getData();
}
$('#btn-newtile').click(function(){callAddMessage()});
// $('#btn-addRow').click(function(){addRow()});
// $('#btn-save').click(getUpdate);
function getData(){
$.getJSON(host + '/api/mock/'+clientUUID, function(data) {
json = data;
checkUuid();
refreshData();
});
}
function checkUuid(){
if(clientUUID == null || clientUUID == undefined || clientUUID == ''){
clientUUID = json[0].clientUUID;
setCookie();
}
}
function getDomain(){
var url = window.location.href;
var arr = url.split("/");
var result = arr[0] + "//" + arr[2];
return result;
}
function httpStatusInvalid(){
value = $('#httpStatus').val();
return value == '';
}
function setDataModified(){
if(httpStatusInvalid()){
$('#btn-save').removeClass('active');
$('#btn-save').off();
document.getElementById("httpStatus").style.backgroundColor = color_red;
return;
}
dataModified = true;
$('#btn-save').addClass('active');
$('#btn-save').click(getUpdate);
document.getElementById("httpStatus").style.backgroundColor = null;
}
//Adding change listener to fields
$('.data-field').change(setModified);
function setDataOrigin(){
dataModified = false;
$('#btn-save').removeClass('active');
$('#btn-save').off();
}
const idToDisplay = function(){
let defaultId = json[0].mockedResponseId;
if(lastId == undefined || lastId == null) return defaultId;
for(let i=0; i<json.length; i++){
if(json[i].mockedResponseId == lastId){
return lastId;
}
}
if(jsonIndex <= json.length && jsonIndex > 0){
jsonIndex -= 1;
return json[jsonIndex].mockedResponseId;
}
return defaultId;
}
function refreshData(){
$("#uuid-input").val(clientUUID);
fillMessageList();
let id = idToDisplay();
loadMessage(id);
}
function setCookie(){
document.cookie = C_UUID + '=' +clientUUID;
document.cookie = C_ID + '=' + lastId;
document.cookie = C_ADV + '=' + advancedVisibility;
}
function loadCookies(){
clientUUID = getCookie(C_UUID);
lastId = getCookie(C_ID);
advancedDisplayed = getCookie(C_ADV) == 'true';
}
function getCookie(cname) {
var name = cname + '=';
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
for(var i = 0; i <ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return '';
}
function callMethodByName(methodObject){
let name = methodObject.name;
let id = methodObject.id;
switch(name){
case addMessageName:
addMessage();
break;
case loadMessageName:
loadMessage(id);
break;
case removeMessageName:
removeMessage(id);
break;
}
}
function updateData(){
var updatedJson = generateJson();
const dataSaved = function () {
setDataOrigin();
refreshData();
savedModalDisplay();
}
$.ajax({
url: host + '/api/mock',
type: 'PUT',
data: JSON.stringify(updatedJson, null, 2),
contentType: "application/json",
}).done(dataSaved);
}
function callAddMessage(){
if(dataModified){
setMethodToCall(addMessageName, null);
dataLossModalDisplay();
}
else {
addMessage();
}
}
function addMessage(){
$.ajax({
url: host + '/api/mock/'+clientUUID,
type: 'POST',
}).done(dataRefresh);
}
function callRemoveMessage(id){
if(dataModified){
setMethodToCall(removeMessageName, id);
dataLossModalDisplay();
}
else {
removeMessage(id);
}
}
function removeMessage(id){
var jsonObject = findJsonById(id);
$.ajax({
url: host + '/api/mock/'+clientUUID + '/' + id,
type: 'DELETE',
}).done(dataRefresh);
}
function clearMock(){
fillStaticFields('','','','');
htable_row = 0;
$('#httpStatusValues').html('');
}
function initializeMock(index){
clearMock();
fillStaticFields(json[index].clientUUID
, json[index].mockedResponseId
, json[index].mediaType
, json[index].messageBody
, json[index].httpStatus);
fillHeaderTable(json[index].httpHeaders);
}
function fillStaticFields(uuid, id, mediaType, body, httpStatus){
let link = createLink(uuid,id);
let linkHtml = '<a class="hyperlink" target="_blank" href="'+link+'">'+link+'</a>';
$('#messageLink').html(linkHtml);
$('#httpStatus').val(httpStatus);
$('#uuid-input').val(uuid);
$('#typeSelector').val(mediaType);
$('#bodyEditor').val(body);
$('#mockedMessageId').html(id);
}
function changeEditionOfUUID(element){
var inputFieldId= "#uuid-input"
var inputFieldDiv = "#uuid-edit-field"
if(element.checked){
$(inputFieldId).removeAttr('disabled');
$(inputFieldDiv).removeClass('disabled');
} else{
$(inputFieldId).attr('disabled', true);
$(inputFieldDiv).addClass('disabled');
}
}
function copyUUIDToClipboard(){
navigator.clipboard.writeText( document.getElementById('uuid-input').value );
}
async function fetchUUIDCheck(givenUUID , strategy){
var newUUID = "UUID" ;
url = host + "/api/mock/check/";
switch(strategy){
case "new":{
await fetch(url + givenUUID+ "/", { method : "GET" })
.then ( response => response.text() )
.then ( data => {
newUUID = data;
} )
break;
}
case "restore":{
await fetch(url + givenUUID + "/" + clientUUID + "/" , { method: "GET" })
.then (response => response.text() )
.then (data => {
newUUID = data;
} )
break;
}
}
return newUUID ;
}
function checkUUIDChars(uuid) {
uuid.replace(/ /g,'')
const regex = new RegExp("^[A-z0-9-]+$");
if(regex.test(uuid) && uuid != ""){
return uuid ;
}
return "invalid";
}
function changeUUID(element){
const uuidStrategy = $('input[name="uuid-validation-type"]:checked').val();
const givenUUID = checkUUIDChars(element.value);
if( givenUUID == clientUUID ){
$("#uuid-input").attr("disabled", true);
uuidChangeModalDisplay("noChg");
return;
}
var newUUID = fetchUUIDCheck(givenUUID , uuidStrategy);
var changeMessage = uuidStrategy;
newUUID
.then( data => {
if (givenUUID == data) {
changeMessage = "success";
}
clientUUID = data;
$("#editable").attr("checked", false);
uuidChangeModalDisplay(changeMessage);
document.cookie = C_UUID + '=' + data ;
} )
loadCookies();
refreshData();
}
function createLink(uuid, id){
var link = host + '/api/mock/r/'+uuid+'/'+id;
return link;
}
function fillHeaderTable(headers){
var innerHTML = buildHeaderMapHtml(headers);
refreshHeaderTable(innerHTML);
}
function refreshHeaderTable(html){
$('#headerMapTable').html(html);
$('.table-map').change(function(){setDataModified()});
$('.btn-hashmap').click(function(){
$(this).closest('tr').remove();
setDataModified();
})
}
function buildHeaderMapHtml(headers){
var innerHTML = '';
for(var key in headers){
innerHTML += buildRowHtml(key, headers[key]);
}
return innerHTML;
}
function addRow(key, value){
var headerMap = $('#headerMapTable');
var headersMapHtml = headerMap.html();
headersMapHtml += buildRowHtml(key, value);
refreshHeaderTable(headersMapHtml);
}
const newRowInput = function(){
const hName = $('#headerKeyInput');
const hValue = $('#headerValueInput');
if(checkIfInputValid(hName.val()) && checkIfInputValid(hValue.val())){
addRow(hName.val(), hValue.val());
hName.val(null);
hValue.val(null);
setDataModified();
}
}
$('#btn-newRow').click(newRowInput);
function checkIfInputValid(input){
return !(input == '' || input == null || input == undefined);
}
function checkIfHeaderEssential(key){
if( key == "Connection" || key == "Keep-Alive" || key == "Date" ){
return true;
}
return false;
}
function buildRowHtml(key, value){
if(checkIfHeaderEssential(key)){
return '' +
'<tr>' +
'<td><input class="key data-field" value="' + key + '" readonly></td>' +
'<td><input class="data-field" value="' + value + '"></td>' +
'</tr>';
}
return '' +
'<tr>' +
'<td><input class="key data-field" value="' + key + '"></td>' +
'<td><input class="data-field" value="' + value + '"></td>' +
'<td><button class="modification-button btn-hashmap"><i class="icon-cancel"></i></button></td>' +
'</tr>';
}
function fillMessageList(){
$("#listItems").html('');
var innerHTML = '';
for(let i=0; i<json.length; i++){
innerHTML += generateMessageTileHtml(json[i].mockedResponseId, json[i].httpStatus, json[i].mediaType);
}
$("#listItems").append(innerHTML);
$('.tile').click(function(e) {
var element = $(this);
var button = element.find('.btn-tile').children().get(0);
if(!(button == e.target)){
callLoadMessage(parseInt($(this).attr('tileid')));
}
});
$('.btn-tile').click(function(){
//
callRemoveMessage($(this).closest('.tile').attr('tileId'));
})
}
function findJsonById(id){
return json[findJsonIndexById(id)];
}
function findJsonIndexById(id){
for(let i=0; i<json.length; i++)
if(id == json[i].mockedResponseId) return i;
}
function callLoadMessage(id){
if(dataModified) {
setMethodToCall(loadMessageName, id);
dataLossModalDisplay();
}
else {
loadMessage(id);
}
}
function loadMessage(id){
if(id == null || id == undefined){
return;
}
lastId = id;
setCookie();
setDataOrigin();
for(let i=0; i<json.length; i++){
if(id == json[i].mockedResponseId){
jsonIndex = i;
initializeMock(jsonIndex);
selectMessage(id);
return;
}
}
}
function selectMessage(id){
const tiles = $('.tile');
tiles.removeClass("active");
$('.tile[tileid="'+id+'"]').addClass("active");
initializeHistory();
refreshHeaderTable(innerHTML);
}
function generateMessageTileHtml(id, httpStatus, mediaType){
var innerHTML = '' +
'<div tileid="' + id + '" class="tile">' +
'<div class="content">' +
'<div class="display-space-between">' +
'<div class="centered-vertically">' +
'<p>Id: ' + id + '</p>' +
'<p>Status: ' + httpStatus + '</p>' +
'</div>' +
'<div>' +
'<button class="modification-button btn-tile"><i class="icon-cancel"></i></button>' +
'</div>' +
'</div>' +
'</div>' +
'</div>';
return innerHTML;
}
const onbuild = function(){
loadCookies();
getData();
if(advancedDisplayed) {
changeAdvancedVisibility();
}
}
$(document).ready(onbuild);
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function generateJson(){
var newJson =
{
clientUUID: json[jsonIndex].clientUUID,
mockedResponseId: json[jsonIndex].mockedResponseId,
mediaType: $('#typeSelector').val(),
messageBody: $('#bodyEditor').val(),
httpStatus: $('#httpStatus').val(),
httpHeaders: {},
};
newJson['httpHeaders'] = convertTableToJson();
json[jsonIndex] = newJson;
return newJson;
}
function convertTableToJson(){
const rows = $('#headerMapTable').children();
var obj = {};
var key;
for(let i=0; i<rows.length; i++){
key = rows.eq(i).children().eq(0).children().eq(0).val();
obj[key] = rows.eq(i).children().eq(1).children().eq(0).val();
}
return obj;
}

View File

@@ -1,5 +0,0 @@
const deleteParent = function(){
$(this).closest('div.tile').remove();
}
$('#test1').click(deleteParent);

View File

@@ -1,58 +0,0 @@
var historyJson = {};
const maxIterations = 200;
function filterHistory(){
var dateFrom = new Date($('#historyFrom').val() + 'T' + $('#historyTimeFrom').val());
var dateTo = new Date($('#historyTo').val() + 'T' + $('#historyTimeTo').val());
loadHistory(dateFrom, dateTo);
}
const startSearch = function(){
filterHistory();
}
$('#btn-searchHistory').click(startSearch);
function loadHistory(dateFrom, dateTo){
var eventRequest = {
clientUUID : json[jsonIndex].clientUUID,
localDateTimeFrom : dateFrom,
localDateTimeTo : dateTo,
mockedResponseId : json[jsonIndex].mockedResponseId
};
$.ajax({
url: host + '/api/event',
type: 'POST',
data: JSON.stringify(eventRequest, null, 2),
contentType: "application/json"
}).done(function(data){
historyJson = data;
displayHistory();
});
}
function getLast24hHistoryData(){
$.getJSON(host + '/api/event/' + clientUUID + '/' + lastId, function(data){
historyJson = data;
displayHistory();
});
}
function historyToHtml(){
var innerHTML = '';
var iterations = historyJson.length <= maxIterations ? historyJson.length : maxIterations;
for(let i=0; i<iterations; i++){
let style = i%2==0 ? ' class="even"' : '';
innerHTML += '<tr' + style + '>' +
'<td>' + historyJson[i].dateTimeStamp + '</td>' +
'<td>' + historyJson[i].interfaceName + '</td>' +
'</tr>';
}
return innerHTML;
}
function displayHistory(){
$('#historyTable tbody').html(historyToHtml());
}

View File

@@ -1,89 +0,0 @@
var modalDisplayed = false;
var methodToCall = {
name: null,
id: null
};
const overlay = $('#overlay');
const savedModal = $('#modal-confirm');
const dataLossModal = $('#modal-query');
const uuidChangeModal = $('#modal-uuidChanged')
const dataLossModalYes = dataLossModal.children().eq(2).children().eq(0);
const dataLossModalNo = dataLossModal.children().eq(2).children().eq(1);
const allModals = $('.modal');
const btnModalClose = $('.modal button');
const closeModals = function() {
hideModal(allModals);
}
const savedModalDisplay = function() {
showModal(savedModal);
setTimeout(closeModals, 2000);
}
const dataLossModalDisplay = function(){
showModal(dataLossModal);
}
const uuidChangeModalDisplay = function(addidionalMessage){
switch(addidionalMessage){
case "success":{
$(".uuid-modal-body").removeClass("active");
$("#changeUUIDSuccess").addClass("active");
break;
}
case "new":{
$(".uuid-modal-body").removeClass("active");
$("#newUUID").addClass("active");
break;
}
case "restore":{
$(".uuid-modal-body").removeClass("active");
$("#restoredUUID").addClass("active");
break;
}
case "noChg":{
$(".uuid-modal-body").removeClass("active");
$("#noChgUUID").addClass("active");
break;
}
}
showModal(uuidChangeModal);
}
function setMethodToCall(name, id){
methodToCall.name = name;
methodToCall.id = id;
}
const dropChangesAndClose = function(){
callMethodByName(methodToCall)
hideModal(dataLossModal);
}
function showModal(jmodal){
if(modalDisplayed) return;
overlay.addClass('active');
jmodal.addClass('active');
modalDisplayed = true;
}
function hideModal(jmodal){
if(!modalDisplayed) return;
if ($(uuidChangeModal).hasClass('active')) window.location.reload();
overlay.removeClass('active');
jmodal.removeClass('active');
modalDisplayed = false;
}
btnModalClose.click(closeModals);
overlay.click(closeModals);
dataLossModalNo.click(closeModals);
dataLossModalYes.click(dropChangesAndClose);

View File

@@ -1,141 +0,0 @@
var advancedVisibility = false;
var selectMenu = $("#selectMenuContent");
var advancedTab = $("#advanced");
var basicID = $("#basicItemData")
var advancedID = $("#advancedItemData");
var advancedUUIDOptions = $("#uuid-validation-strategy");
var focusedField = false;
function changeAdvancedVisibility(){
if(advancedVisibility){
selectMenu.removeClass('active');
advancedTab.removeClass('active');
advancedID.removeClass('active');
advancedUUIDOptions.removeClass('active');
basicID.addClass('active');
advancedVisibility = false;
}
else {
selectMenu.addClass('active');
advancedTab.addClass('active');
advancedID.addClass('active');
advancedUUIDOptions.addClass('active');
basicID.removeClass('active');
advancedVisibility = true;
}
setCookie();
}
const historyFilter = $('#history-filter');
const historyFilterSwitch = function(){
historyFilter.toggleClass('active');
}
$("#optional").click(changeAdvancedVisibility);
$('#historyTab').click(showHistory);
$('#btn-history-filter').click(historyFilterSwitch);
const tabitem = $('.tabitem');
function showHistory(){
$('#headersTab').click(showHeaders);
tabitem.removeClass('active');
$('.tabcontent').removeClass('active');
$('#history').addClass('active');
$('#historyTab').addClass('active');
$('#historyTab').off('click');
initializeHistory();
}
function initializeHistory(){
historyFilter.removeClass('active');
getLast24hHistoryData();
}
function showHeaders(){
$('#historyTab').click(showHistory);
tabitem.removeClass('active');
$('.tabcontent').removeClass('active');
$('#headers').addClass('active');
$('#headersTab').addClass('active');
$('#headersTab').off('click');
}
function focusInTip(element){
showTip(element);
focusedField = true;
}
function focusOutTip(element){
focusedField = false;
hidTip(element);
}
function hidTip(element){
if(focusedField) return;
$('#'+element).removeClass('active');
}
function showTip(element){
if(focusedField) return;
$('.tip').removeClass('active');
$('#'+element).addClass('active');
}
$('#messageLink').mouseover(function(){showTip('messageLinkTip')});
$('#messageLink').mouseleave(function(){hidTip('messageLinkTip')});
$('#httpStatus').mouseover(function(){showTip('httpStatusTip')});
$('#httpStatus').focusin(function(){focusInTip('httpStatusTip')});
$('#httpStatus').mouseleave(function(){hidTip('httpStatusTip')});
$('#httpStatus').focusout(function(){focusOutTip('httpStatusTip')});
$('#typeSelector').mouseover(function(){showTip('typeSelectorTip')});
$('#typeSelector').focusin(function(){focusInTip('typeSelectorTip')});
$('#typeSelector').mouseleave(function(){hidTip('typeSelectorTip')});
$('#typeSelector').focusout(function(){focusOutTip('typeSelectorTip')});
$('#bodyEditor').mouseover(function(){showTip('bodyEditorTip')});
$('#bodyEditor').focusin(function(){focusInTip('bodyEditorTip')});
$('#bodyEditor').mouseleave(function(){hidTip('bodyEditorTip')});
$('#bodyEditor').focusout(function(){focusOutTip('bodyEditorTip')});
$('#headersTab').mouseover(function(){showTip('headersTabTip')});
$('#headersTab').mouseleave(function(){hidTip('headersTabTip')});
$('#historyTab').mouseover(function(){showTip('historyTabTip')});
$('#historyTab').mouseleave(function(){hidTip('historyTabTip')});
$('#headerKeyInput').mouseover(function(){showTip('newHeaderTip')});
$('#headerKeyInput').focusin(function(){focusInTip('newHeaderTip')});
$('#headerKeyInput').mouseleave(function(){hidTip('newHeaderTip')});
$('#headerKeyInput').focusout(function(){focusOutTip('newHeaderTip')});
$('#headerValueInput').mouseover(function(){showTip('newHeaderTip')});
$('#headerValueInput').focusin(function(){focusInTip('newHeaderTip')});
$('#headerValueInput').mouseleave(function(){hidTip('newHeaderTip')});
$('#headerValueInput').focusout(function(){focusOutTip('newHeaderTip')});
$('#btnSave').mouseover(function(){showTip('btnSaveTip');});
$('#btnSave').focusin(function(){focusInTip('btnSaveTip')});
$('#btnSave').mouseleave(function(){hidTip('btnSaveTip')});
$('#btnSave').focusout(function(){focusOutTip('btnSaveTip')});
$('#new-tile').mouseover(function(){showTip('btn-newTileTip');});
$('#new-tile').mouseleave(function(){hidTip('btn-newTileTip')});
$('#new-tile').focusout(function(){focusOutTip('btn-newTileTip')});
$('#listItems').mouseover(function(){showTip('messagesTip');});
$('#listItems').mouseleave(function(){hidTip('messagesTip')});
$('#uuid-edit-field').mouseover(function(){ showTip('UUIDFieldTip') });
$('#uuid-edit-field').mouseleave(function(){ hidTip('UUIDFieldTip') });
$('#uuid-validation-strategy').mouseover(function(){ showTip('UUIDValidationStrategyTip') });
$('#uuid-validation-strategy').mouseleave(function(){ hidTip('UUIDValidationStrategyTip') });
$('#editableBlock').mouseover( function(){ showTip('UUIDEditionTip') } );
$('#editableBlock').mouseleave(function(){ hidTip('UUIDEditionTip') });

View File

@@ -2,12 +2,11 @@ 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.*;
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;
@@ -32,12 +31,19 @@ public class SparkApplication {
.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));
registry.registerController(new XsdController(gson, logger));
registry.registerController(new XPathController(gson, logger));
registry.registerController(new XsltController(gson, logger));
registry.registerController(new JsonController());
registry.registerController(new ProcessorInfoController(logger, saxon, xalan));
registry.registerController(new XmlController(gson, logger, saxon, xalan));
registry.registerController(new MultipleXMLController(gson,logger, saxon));
registry.registerController(new JsonController(gson, jsongson, logger));
registry.register();

View File

@@ -1,26 +1,32 @@
package com.r11.tools.controller;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
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 Gson prettyGson = new GsonBuilder()
.disableHtmlEscaping()
.setPrettyPrinting()
.create();
private final Logger logger;
private final Gson gson = new GsonBuilder()
.disableHtmlEscaping()
.create();
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) {
@@ -28,24 +34,25 @@ public class JsonController implements RestController {
JsonObject responseJson = new JsonObject();
try {
JsonObject requestJson = this.gson.fromJson(request.body(), JsonObject.class);
Object requestJson = this.gson.fromJson(request.body(), Object.class);
response.status(200);
responseJson.addProperty("data", this.prettyGson.toJson(requestJson));
responseJson.addProperty("result", this.prettyGson.toJson(requestJson));
responseJson.addProperty("time", System.currentTimeMillis() - startProcess);
response.body(this.prettyGson.toJson(responseJson));
} catch (Exception e) {
this.logger.error("Error on formatting Json " + e);
Throwable cause = e.getCause();
response.status(500);
response.status(400);
responseJson.addProperty("data", cause == null ? e.getMessage() : cause.getMessage());
responseJson.addProperty("result", 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")
@@ -54,23 +61,25 @@ public class JsonController implements RestController {
JsonObject responseJson = new JsonObject();
try {
JsonObject requestJson = this.prettyGson.fromJson(request.body(), JsonObject.class);
Object requestJson = this.prettyGson.fromJson(request.body(), Object.class);
response.status(200);
responseJson.addProperty("data", this.gson.toJson(requestJson));
responseJson.addProperty("result", this.gson.toJson(requestJson));
responseJson.addProperty("time", System.currentTimeMillis() - startProcess);
response.body(this.gson.toJson(responseJson));
} catch (Exception e) {
this.logger.error("Error on minimizing Json " + e);
Throwable cause = e.getCause();
response.status(500);
response.status(400);
responseJson.addProperty("data", cause == null ? e.getMessage() : cause.getMessage());
responseJson.addProperty("result", 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.");
}
}

View File

@@ -0,0 +1,96 @@
package com.r11.tools.controller;
import com.google.gson.Gson;
import com.r11.tools.controller.internal.*;
import com.r11.tools.model.XMLMultipleFilesBody;
import com.r11.tools.model.XMLResponseBody;
import com.r11.tools.xml.XmlEngine;
import org.apache.logging.log4j.Logger;
import spark.Request;
import spark.Response;
@GlobalControllerManifest
public class MultipleXMLController implements RestController {
private final Gson gson;
private final Logger logger;
private final XmlEngine engine;
public MultipleXMLController(Gson gson, Logger logger, XmlEngine engine) {
this.gson = gson;
this.logger = logger;
this.engine = engine;
}
@ScopedControllerManifest(method = HandlerType.POST, path = "/multiple/xslt")
public void acceptRequestXslt(Request request, Response response) {
acceptRequest(request, response, XmlJobType.XSLT);
}
private void acceptRequest(Request request, Response response, XmlJobType xmlJobType) {
XMLMultipleFilesBody requestBody;
try {
requestBody = this.gson.fromJson(request.body(), XMLMultipleFilesBody.class);
} catch (Exception e) {
requestErrorResponse(response, e);
return;
}
processRequest(new MultipleXmlJob(response, requestBody, engine, xmlJobType));
}
private void processRequest(MultipleXmlJob xmlJob) {
XMLResponseBody responseBody = null;
long timeStart = System.currentTimeMillis();
long duration;
try {
responseBody = processData(xmlJob);
duration = System.currentTimeMillis() - timeStart;
responseBody.setDuration(duration);
xmlJob.getResponse().status(200);
this.logger.info("Request (" + xmlJob.getXmlJobType() + ", " +
xmlJob.getEngine().getVersion() +
") processed in " + duration + " ms.");
} catch (Exception ex) {
responseBody = processingErrorResponse(ex, xmlJob);
} finally {
xmlJob.getResponse().body(this.gson.toJson(responseBody));
}
}
private XMLResponseBody processData(MultipleXmlJob xmlJob) throws Exception {
XmlEngine engine = xmlJob.getEngine();
XMLMultipleFilesBody requestBody = xmlJob.getRequestBody();
String result = engine.processXSLT(requestBody.getData(), requestBody.getProcessorData());
return new XMLResponseBody(result, "OK", requestBody.getVersion());
}
private XMLResponseBody processingErrorResponse(Exception ex, MultipleXmlJob xmlJob) {
XmlEngine engine = xmlJob.getEngine();
XmlJobType xmlJobType = xmlJob.getXmlJobType();
Response response = xmlJob.getResponse();
XMLResponseBody responseBody =
new XMLResponseBody(ex.getMessage(), "ERR", engine.getVersion(), -1);
response.status(400);
this.logger.error("Error on processing " + xmlJobType + " using " + engine.getVersion() + ". " + ex);
return responseBody;
}
private void requestErrorResponse(Response response, Exception ex) {
XMLResponseBody responseBody = new XMLResponseBody(ex.getMessage(), "ERR", "N/A", -1);
response.status(400);
response.body(this.gson.toJson(responseBody));
}
}

View File

@@ -5,6 +5,7 @@ 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;
@@ -13,9 +14,13 @@ import spark.Response;
public class ProcessorInfoController implements RestController {
private final Logger logger;
private final XmlEngine saxon;
private final XmlEngine xalan;
public ProcessorInfoController(Logger logger) {
public ProcessorInfoController(Logger logger, XmlEngine saxon, XmlEngine xalan) {
this.logger = logger;
this.saxon = saxon;
this.xalan = xalan;
}
/**
@@ -24,8 +29,8 @@ public class ProcessorInfoController implements RestController {
@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());
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());

View File

@@ -1,122 +0,0 @@
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 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;
public XPathController(Gson gson, Logger logger) {
this.gson = gson;
this.logger = logger;
}
@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();
String tmp = "";
long timeStart;
long duration;
if (processor == null) {
response.body("saxon, xalan");
return;
}
JsonObject responseJson = new JsonObject();
switch (processor) {
case "saxon":
response.header("processor", "Saxon " + Saxon.getVersion() + " " + version + " over s9api");
timeStart = System.currentTimeMillis();
try {
tmp = Saxon.processXPath(data, query, version).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));
return;
case "xalan":
response.header("processor", Xalan.getVersion());
timeStart = System.currentTimeMillis();
try {
tmp = Xalan.processXPath(data, query).trim();
response.status(200);
responseJson.addProperty("result", tmp);
responseJson.addProperty("status", "OK");
} 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));
return;
default:
response.body("saxon, xalan");
}
}
}

View File

@@ -0,0 +1,173 @@
package com.r11.tools.controller;
import com.google.gson.Gson;
import com.r11.tools.controller.internal.*;
import com.r11.tools.model.XMLRequestBody;
import com.r11.tools.model.XMLResponseBody;
import com.r11.tools.model.XPathQueryResult;
import com.r11.tools.xml.XmlEngine;
import org.apache.logging.log4j.Logger;
import spark.Request;
import spark.Response;
/**
* Controller used to handle XML tools: XPath, XSD validation, XQuery and XSLT
* @author Adam Bem
*/
@GlobalControllerManifest
public class XmlController implements RestController {
private final Gson gson;
private final Logger logger;
private final XmlEngine saxon;
private final XmlEngine xalan;
public XmlController(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 acceptRequestXPath(Request request, Response response) {
acceptRequest(request, response, XmlJobType.XPath);
}
@ScopedControllerManifest(method = HandlerType.POST, path = "/xquery")
public void acceptRequestXQuery(Request request, Response response) {
acceptRequest(request, response, XmlJobType.XQuery);
}
@ScopedControllerManifest(method = HandlerType.POST, path = "/xsd")
public void acceptRequestXsd(Request request, Response response) {
acceptRequest(request, response, XmlJobType.XSD);
}
@ScopedControllerManifest(method = HandlerType.POST, path = "/xslt")
public void acceptRequestXslt(Request request, Response response) {
acceptRequest(request, response, XmlJobType.XSLT);
}
private void acceptRequest(Request request, Response response, XmlJobType xmlJobType) {
XMLRequestBody requestBody;
try {
requestBody = this.gson.fromJson(request.body(), XMLRequestBody.class);
} catch (Exception e) {
requestErrorResponse(response, e);
return;
}
if (requestBody.getProcessor() == null) {
invalidEngineSelectedResponse(response);
return;
}
switch (requestBody.getProcessor().toLowerCase()) {
case "saxon":
processRequest(new XmlJob(response, requestBody, saxon, xmlJobType));
return;
case "xalan":
processRequest(new XmlJob(response, requestBody, xalan, xmlJobType));
return;
default:
invalidEngineSelectedResponse(response);
}
}
private void processRequest(XmlJob xmlJob) {
XMLResponseBody responseBody = null;
long timeStart = System.currentTimeMillis();
long duration;
try {
responseBody = processData(xmlJob);
duration = System.currentTimeMillis() - timeStart;
responseBody.setDuration(duration);
xmlJob.getResponse().status(200);
this.logger.info("Request (" + xmlJob.getXmlJobType() + ", " +
xmlJob.getEngine().getVersion() +
") processed in " + duration + " ms.");
} catch (Exception ex) {
responseBody = processingErrorResponse(ex, xmlJob);
} finally {
xmlJob.getResponse().body(this.gson.toJson(responseBody));
}
}
private XMLResponseBody processData(XmlJob xmlJob) throws Exception {
if (xmlJob.getXmlJobType() == XmlJobType.XPath)
return processXPath(xmlJob);
else
return processOther(xmlJob);
}
private XMLResponseBody processXPath(XmlJob xmlJob) throws Exception {
XmlEngine engine = xmlJob.getEngine();
XMLRequestBody requestBody = xmlJob.getRequestBody();
XPathQueryResult xPathQueryResult =
engine.processXPath(requestBody.getData(), requestBody.getProcessorData(), requestBody.getVersion());
return new XMLResponseBody(xPathQueryResult.getData().trim(),
"OK", engine.getVersion(), xPathQueryResult.getType());
}
private XMLResponseBody processOther(XmlJob xmlJob) throws Exception {
XmlEngine engine = xmlJob.getEngine();
XMLRequestBody requestBody = xmlJob.getRequestBody();
String result = null;
switch (xmlJob.getXmlJobType()) {
case XSLT:
result = engine.processXSLT(requestBody.getData(), requestBody.getProcessorData());
break;
case XSD:
result = engine.validate(requestBody.getData(), requestBody.getProcessorData()).trim();
break;
case XQuery:
result = engine.executeXQuery(requestBody.getData(),
requestBody.getProcessorData(),
requestBody.getVersion());
break;
}
return new XMLResponseBody(result, "OK", requestBody.getVersion());
}
private XMLResponseBody processingErrorResponse(Exception ex, XmlJob xmlJob) {
XmlEngine engine = xmlJob.getEngine();
XmlJobType xmlJobType = xmlJob.getXmlJobType();
Response response = xmlJob.getResponse();
XMLResponseBody responseBody =
new XMLResponseBody(ex.getMessage(), "ERR", engine.getVersion(), -1);
response.status(400);
this.logger.error("Error on processing " + xmlJobType + " using " + engine.getVersion() + ". " + ex);
return responseBody;
}
private void invalidEngineSelectedResponse(Response response) {
XMLResponseBody responseBody =
new XMLResponseBody("Valid engines are: saxon, xalan", "ERR", "N/A", -1);
response.body(this.gson.toJson(responseBody));
response.status(400);
}
private void requestErrorResponse(Response response, Exception ex) {
XMLResponseBody responseBody = new XMLResponseBody(ex.getMessage(), "ERR", "N/A", -1);
response.status(400);
response.body(this.gson.toJson(responseBody));
}
}

View File

@@ -1,78 +0,0 @@
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 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;
public XsdController(Gson gson, Logger logger) {
this.gson = gson;
this.logger = logger;
}
@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;
}
}

View File

@@ -1,119 +0,0 @@
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 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;
public XsltController(Gson gson, Logger logger) {
this.gson = gson;
this.logger = logger;
}
@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;
}
String tmp;
long timeStart;
long duration;
JsonObject responseJson = new JsonObject();
switch (processor) {
case "saxon":
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));
return;
case "xalan":
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));
return;
default:
response.body("saxon, xalan");
}
}
}

View File

@@ -0,0 +1,36 @@
package com.r11.tools.controller.internal;
import com.r11.tools.model.XMLMultipleFilesBody;
import com.r11.tools.xml.XmlEngine;
import spark.Response;
public class MultipleXmlJob {
private final Response response;
private final XMLMultipleFilesBody requestBody;
private final XmlEngine engine;
private final XmlJobType xmlJobType;
public MultipleXmlJob(Response response, XMLMultipleFilesBody requestBody, XmlEngine engine, XmlJobType xmlJobType) {
this.response = response;
this.requestBody = requestBody;
this.engine = engine;
this.xmlJobType = xmlJobType;
}
public Response getResponse() {
return response;
}
public XMLMultipleFilesBody getRequestBody() {
return requestBody;
}
public XmlEngine getEngine() {
return engine;
}
public XmlJobType getXmlJobType() {
return xmlJobType;
}
}

View File

@@ -0,0 +1,35 @@
package com.r11.tools.controller.internal;
import com.r11.tools.model.XMLRequestBody;
import com.r11.tools.xml.XmlEngine;
import spark.Response;
public class XmlJob {
private final Response response;
private final XMLRequestBody requestBody;
private final XmlEngine engine;
private final XmlJobType xmlJobType;
public XmlJob(Response response, XMLRequestBody requestBody, XmlEngine engine, XmlJobType xmlJobType) {
this.response = response;
this.requestBody = requestBody;
this.engine = engine;
this.xmlJobType = xmlJobType;
}
public Response getResponse() {
return response;
}
public XMLRequestBody getRequestBody() {
return requestBody;
}
public XmlEngine getEngine() {
return engine;
}
public XmlJobType getXmlJobType() {
return xmlJobType;
}
}

View File

@@ -0,0 +1,8 @@
package com.r11.tools.controller.internal;
public enum XmlJobType {
XPath("XPath"), XSD("XSD"), XQuery("XQuery"), XSLT("XSLT");
XmlJobType(String type) {
}
}

View File

@@ -0,0 +1,32 @@
package com.r11.tools.model;
import com.google.gson.annotations.SerializedName;
public class XMLMultipleFilesBody {
@SerializedName("data")
private XMLMultipleFilesData[] data;
@SerializedName("processorData")
private String processorData;
@SerializedName("processor")
private String processor;
@SerializedName("version")
private String version;
public String getProcessorData() {
return processorData;
}
public String getProcessor() {
return processor;
}
public String getVersion() {
return version;
}
public XMLMultipleFilesData[] getData() {
return data;
}
}

View File

@@ -0,0 +1,18 @@
package com.r11.tools.model;
import com.google.gson.annotations.SerializedName;
public class XMLMultipleFilesData {
@SerializedName("fileName")
private String filename;
@SerializedName("fileData")
private String data;
public String getFilename() {
return filename;
}
public String getData() {
return data;
}
}

View File

@@ -0,0 +1,34 @@
package com.r11.tools.model;
import com.google.gson.annotations.SerializedName;
/**
* POJO class used to contain body of XML related requests
* @author Adam Bem
*/
public class XMLRequestBody {
@SerializedName("data")
private String data;
@SerializedName("processorData")
private String processorData;
@SerializedName("processor")
private String processor;
@SerializedName("version")
private String version;
public String getData() {
return data;
}
public String getProcessorData() {
return processorData;
}
public String getProcessor() {
return processor;
}
public String getVersion() {
return version;
}
}

View File

@@ -0,0 +1,71 @@
package com.r11.tools.model;
public class XMLResponseBody {
private String result;
private String status;
private String processor;
private long duration;
// Optional
private String type;
public XMLResponseBody(String result, String status, String processor) {
this.result = result;
this.status = status;
this.processor = processor;
}
public XMLResponseBody(String result, String status, String processor, long duration) {
this.result = result;
this.status = status;
this.processor = processor;
this.duration = duration;
}
public XMLResponseBody(String result, String status, String processor, String type) {
this.result = result;
this.status = status;
this.processor = processor;
this.type = type;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getProcessor() {
return processor;
}
public void setProcessor(String processor) {
this.processor = processor;
}
public long getDuration() {
return duration;
}
public void setDuration(long duration) {
this.duration = duration;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}

View File

@@ -0,0 +1,22 @@
package com.r11.tools.model;
/**
* 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;
}
}

View File

@@ -1,16 +1,80 @@
package com.r11.tools.xml;
import com.r11.tools.model.XMLMultipleFilesData;
import com.r11.tools.model.XPathQueryResult;
import net.sf.saxon.s9api.*;
import javax.xml.transform.stream.StreamSource;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Comparator;
import java.util.UUID;
/**
* Handler for Saxon engine
* @author Wojciech Czop
*/
public class Saxon {
public class Saxon implements XmlEngine{
/**
* Transforms many XML documents via XSLT.
* @param data XML Files to be transformed.
* @param transform XSLT
* @return transformed xml
* @throws SaxonApiException thrown on stylesheet or transformation error
* @throws IOException thrown when file does not exist, or cannot be read.
*/
public String processXSLT(XMLMultipleFilesData[] data, String transform) throws SaxonApiException, IOException{
Processor processor = new Processor(false);
XsltCompiler compiler = processor.newXsltCompiler();
String filesPath = "/tmp/"+UUID.randomUUID()+"/";
try{
createXMLFilesFromData(data, filesPath);
Path transformPath = createXSLTFileAndReturnPath(transform,filesPath);
XsltExecutable stylesheet = compiler.compile( new StreamSource( transformPath.toFile() ));
StringWriter sw = new StringWriter();
Serializer out = processor.newSerializer(sw);
out.setOutputProperty(Serializer.Property.METHOD, "xml");
out.setOutputProperty(Serializer.Property.INDENT, "yes");
Xslt30Transformer transformer = stylesheet.load30();
transformer.transform( new StreamSource( new File(filesPath+data[0].getFilename()) ) , out );
return sw.toString();
} finally {
deleteTemporaryFiles(filesPath);
}
}
private void createXMLFilesFromData( XMLMultipleFilesData[] data , String filesPath ) throws IOException {
Files.createDirectories(Paths.get(filesPath));
for (XMLMultipleFilesData fileData : data) {
Path filePath = Files.createFile( Paths.get(filesPath + fileData.getFilename() ) );
try (FileWriter writer = new FileWriter(filePath.toFile())) {
writer.write(fileData.getData());
}
}
}
private Path createXSLTFileAndReturnPath( String xsltTransform, String filesPath ) throws IOException {
Path transformPath = Files.createFile( Paths.get(filesPath + "transform.xsl") );
FileWriter writer = new FileWriter(transformPath.toFile());
writer.write(xsltTransform);
writer.close();
return transformPath;
}
private void deleteTemporaryFiles(String filesPath) throws IOException {
Files
.walk( Paths.get(filesPath) )
.sorted(Comparator.reverseOrder())
.map(Path::toFile)
.forEach(File::delete);
}
/**
* Transforms string containing xml document via xslt
@@ -19,7 +83,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)));
@@ -33,15 +97,43 @@ public class Saxon {
return sw.toString();
}
@Override
public String validate(String data, String xsd) {
throw new UnsupportedOperationException();
}
/**
* This method evaluates XQuery expression on given xml
* @param data xml
* @param xquery expression
* @return
* @throws Exception
*/
@Override
public String executeXQuery(String data, String xquery, String version) throws Exception {
Processor processor = new Processor(false);
XQueryCompiler compiler = processor.newXQueryCompiler();
compiler.setLanguageVersion(version);
XQueryExecutable executable = compiler.compile(xquery);
XQueryEvaluator evaluator = executable.load();
evaluator.setSource(new StreamSource(new StringReader(data)));
XdmValue result = evaluator.evaluate();
return result.toString();
}
/**
* Process xpath and return either node or wrapped atomic value
* @param data xml to be querried
* @param query xpath queryy
* @param data xml to be processed
* @param query xpath query
* @param version processor version
* @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();
@@ -61,7 +153,7 @@ public class Saxon {
sb.append(xdmItem);
sb.append('\n');
}
return sb.toString();
return new XPathQueryResult(sb.toString(), "N/A");
}
@@ -69,7 +161,7 @@ public class Saxon {
* Returns version of the processor
* @return version of the processor
*/
public static String getVersion() {
return new Processor(false).getSaxonProductVersion();
public String getVersion() {
return "Saxon " + new Processor(false).getSaxonProductVersion();
}
}

View File

@@ -1,7 +1,8 @@
package com.r11.tools.xml;
import com.r11.tools.model.XMLMultipleFilesData;
import com.r11.tools.model.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;
@@ -17,13 +18,16 @@ import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.*;
import java.io.ByteArrayOutputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.StringWriter;
/**
* Handler for Xalan engine
* @author Wojciech Czop
*/
public class Xalan {
public class Xalan implements XmlEngine{
/**
* Transforms string containing xml document via xslt
@@ -32,7 +36,7 @@ public class Xalan {
* @return transformed xml
* @throws Exception thrown on stylesheet or transformation errors
*/
public static String processXSLT(String data, String transform) throws Exception{
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)));
@@ -50,13 +54,18 @@ public class Xalan {
return sw.toString();
}
private static boolean isTextNode(Node n) {
private boolean isTextNode(Node n) {
if (n == null)
return false;
short nodeType = n.getNodeType();
return nodeType == Node.CDATA_SECTION_NODE || nodeType == Node.TEXT_NODE;
}
@Override
public String processXSLT(XMLMultipleFilesData[] data, String transform) throws Exception {
throw new UnsupportedOperationException("Xalan does not support multiple files XSLT processing");
}
/**
* Process xpath and return either node or wrapped atomic value
* @param data xml
@@ -64,7 +73,7 @@ public class Xalan {
* @return xml processed using given xpath
* @throws Exception thrown on node building errors or invalid xpath
*/
public static String processXPath(String data, String transform) throws Exception {
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));
@@ -81,7 +90,7 @@ public class Xalan {
NodeIterator nl = XPathAPI.selectNodeIterator(doc, transform);
// Serialize the found nodes to result object.
StringBuilder result = new StringBuilder();
StringBuilder resultString = new StringBuilder();
Node n;
while ((n = nl.nextNode())!= null) {
StringBuilder sb;
@@ -90,18 +99,19 @@ public class Xalan {
// single XPath text node. Coalesce all contiguous text nodes
// at this level
for (Node nn = n.getNextSibling(); isTextNode(nn); nn = nn.getNextSibling()) {
result.append(nn.getNodeValue());
resultString.append(nn.getNodeValue());
}
} else {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
serializer.transform(new DOMSource(n), new StreamResult(new OutputStreamWriter(outputStream)));
result.append(outputStream);
resultString.append(outputStream);
}
result.append("\n");
resultString.append("\n");
}
return result.toString();
return new XPathQueryResult(resultString.toString(), "node");
} catch (TransformerException e) {
return XPathAPI.eval(doc, transform).toString();
String returnData = XPathAPI.eval(doc, transform).toString();
return new XPathQueryResult(returnData, "string");
}
}
@@ -110,7 +120,7 @@ public class Xalan {
* Returns version of the processor
* @return version of the processor
*/
public static String getVersion(){
public String getVersion(){
return org.apache.xalan.Version.getVersion();
}
@@ -121,7 +131,7 @@ public class Xalan {
* @return statement of validity
* @throws Exception thrown on invalid xsd schema or xml
*/
public static String validate(String data, String xsd) throws Exception{
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
@@ -131,4 +141,9 @@ public class Xalan {
validator.validate(dataSource);
return "XML file is valid";
}
@Override
public String executeXQuery(String data, String xquery, String version) throws Exception {
throw new UnsupportedOperationException("Xalan doesn't support XQuery evaluation");
}
}

View File

@@ -0,0 +1,17 @@
package com.r11.tools.xml;
import com.r11.tools.model.XMLMultipleFilesData;
import com.r11.tools.model.XPathQueryResult;
public interface XmlEngine {
String processXSLT(XMLMultipleFilesData[] data, String transform) throws Exception;
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;
String executeXQuery(String data, String xquery, String version) throws Exception;
public String getVersion();
}

28
Frontend/.dockerignore Normal file
View File

@@ -0,0 +1,28 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

15
Frontend/.eslintrc.cjs Normal file
View File

@@ -0,0 +1,15 @@
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true,
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript',
'@vue/eslint-config-prettier/skip-formatting'
],
parserOptions: {
ecmaVersion: 'latest'
}
}

28
Frontend/.gitignore vendored Normal file
View File

@@ -0,0 +1,28 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@@ -0,0 +1,8 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": false,
"tabWidth": 2,
"singleQuote": true,
"printWidth": 100,
"trailingComma": "none"
}

View File

@@ -1,16 +1,30 @@
FROM nginx:stable-alpine
FROM node:20.9.0-bullseye-slim as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY ./ .
RUN npm run build
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
RUN mkdir -p /scripts
COPY insert_version.sh /scripts/
WORKDIR /scripts
RUN chmod +x insert_version.sh
RUN ./insert_version.sh
FROM nginx:stable-alpine3.17-slim as production-stage
RUN mkdir /app
RUN apk add --no-cache tzdata
ENV TZ Europe/Warsaw
COPY --from=build-stage /app/dist /usr/share/nginx/html
COPY ./nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
EXPOSE 443
FROM node:20.9.0-bullseye-slim as dev
WORKDIR /app
COPY package*.json ./
RUN npm install
ENV HOST=0.0.0.0
COPY . .
EXPOSE 8080
CMD ["npm", "run", "dev"]

46
Frontend/README.md Normal file
View File

@@ -0,0 +1,46 @@
# new-frontend
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
## Type Support for `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
1. Disable the built-in TypeScript Extension
1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
## Customize configuration
See [Vite Configuration Reference](https://vitejs.dev/config/).
## Project Setup
```sh
npm install
```
### Compile and Hot-Reload for Development
```sh
npm run dev
```
### Type-Check, Compile and Minify for Production
```sh
npm run build
```
### Lint with [ESLint](https://eslint.org/)
```sh
npm run lint
```

View File

@@ -1,6 +0,0 @@
@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');

View File

@@ -1,14 +0,0 @@
<?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="&#xe801;" 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="&#xe802;" 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>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,59 +0,0 @@
@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'; } /* '' */

View File

@@ -1,145 +0,0 @@
@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#frame {
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;
}

View File

@@ -1,69 +0,0 @@
.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
}

View File

@@ -1,42 +0,0 @@
@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;
}

View File

@@ -1,14 +0,0 @@
<?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="&#xe801;" 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="&#xe802;" 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>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,59 +0,0 @@
@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'; } /* '' */

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