├── .classpath ├── .gitignore ├── .project ├── .settings ├── org.eclipse.jdt.core.prefs └── org.eclipse.m2e.core.prefs ├── .travis.yml ├── LICENSE ├── README.md ├── api └── api.thrift ├── assembly └── distribution.xml ├── bin └── start.bat ├── conf ├── audit4j.conf.yml ├── server.config.yml └── trust │ ├── cert.cer │ ├── keystore.jks │ └── truststore.jks ├── lock └── server.lock ├── pom.xml └── src ├── main ├── java │ └── org │ │ └── audit4j │ │ └── microservice │ │ ├── AppRunningChecker.java │ │ ├── Main.java │ │ ├── ServerConfiguration.java │ │ ├── ServerContext.java │ │ ├── core │ │ ├── Ack.java │ │ ├── Configuration.java │ │ ├── ConfigurationManager.java │ │ ├── Context.java │ │ ├── ContextAware.java │ │ ├── EventReceiver.java │ │ ├── EventReceiverImpl.java │ │ ├── HTTPServer.java │ │ └── Transport.java │ │ ├── transport │ │ ├── AuditServerHandler.java │ │ ├── Serializer.java │ │ ├── SerializerImpl.java │ │ ├── WebSocketTransportServer.java │ │ ├── WebsocketHandler.java │ │ └── thrift │ │ │ ├── TAck.java │ │ │ ├── TAckTransformer.java │ │ │ ├── TAuditEvent.java │ │ │ ├── TAuditEventTransformer.java │ │ │ ├── TAuditHandler.java │ │ │ ├── TAuditService.java │ │ │ ├── TEventMeta.java │ │ │ ├── TField.java │ │ │ └── ThriftTransportServer.java │ │ ├── util │ │ └── KeyGenerator.java │ │ └── web │ │ ├── CustomAuth.java │ │ ├── CustomAuthImpl.java │ │ ├── CustomUser.java │ │ ├── VertxServer.java │ │ ├── WebRouter.java │ │ └── rest │ │ ├── RESTAuditEventHandler.java │ │ └── RestRouter.java └── resources │ ├── log4j.xml │ └── webroot │ ├── css │ ├── sb-admin.css │ └── sb-admin.min.css │ ├── dashboard │ └── index.html │ ├── index.html │ ├── js │ ├── sb-admin-charts.js │ ├── sb-admin-charts.min.js │ ├── sb-admin-datatables.js │ ├── sb-admin-datatables.min.js │ ├── sb-admin.js │ └── sb-admin.min.js │ ├── login.html │ ├── pug │ ├── blank.pug │ ├── cards.pug │ ├── charts.pug │ ├── forgot-password.pug │ ├── includes │ │ ├── css │ │ │ ├── core.pug │ │ │ └── custom.pug │ │ ├── footer.pug │ │ ├── js │ │ │ ├── core.pug │ │ │ └── custom.pug │ │ ├── modals │ │ │ └── logout.pug │ │ ├── navbar.pug │ │ └── scroll-to-top.pug │ ├── index.pug │ ├── login.pug │ ├── navbar.pug │ ├── register.pug │ └── tables.pug │ ├── scss │ ├── _cards.scss │ ├── _footer.scss │ ├── _global.scss │ ├── _login.scss │ ├── _mixins.scss │ ├── _utilities.scss │ ├── _variables.scss │ ├── navbar │ │ ├── _navbar_colors.scss │ │ ├── _navbar_fixed.scss │ │ ├── _navbar_global.scss │ │ ├── _navbar_static.scss │ │ └── _navbar_toggle.scss │ └── sb-admin.scss │ └── vendor │ ├── bootstrap │ ├── css │ │ ├── bootstrap-grid.css │ │ ├── bootstrap-grid.min.css │ │ ├── bootstrap-reboot.css │ │ ├── bootstrap-reboot.min.css │ │ ├── bootstrap.css │ │ └── bootstrap.min.css │ └── js │ │ ├── bootstrap.bundle.js │ │ ├── bootstrap.bundle.min.js │ │ ├── bootstrap.js │ │ └── bootstrap.min.js │ ├── chart.js │ ├── Chart.bundle.js │ ├── Chart.bundle.min.js │ ├── Chart.js │ └── Chart.min.js │ ├── datatables │ ├── dataTables.bootstrap4.css │ ├── dataTables.bootstrap4.js │ └── jquery.dataTables.js │ ├── font-awesome │ ├── css │ │ ├── font-awesome.css │ │ └── font-awesome.min.css │ ├── fonts │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ └── fontawesome-webfont.woff2 │ ├── less │ │ ├── animated.less │ │ ├── bordered-pulled.less │ │ ├── core.less │ │ ├── fixed-width.less │ │ ├── font-awesome.less │ │ ├── icons.less │ │ ├── larger.less │ │ ├── list.less │ │ ├── mixins.less │ │ ├── path.less │ │ ├── rotated-flipped.less │ │ ├── screen-reader.less │ │ ├── stacked.less │ │ └── variables.less │ └── scss │ │ ├── _animated.scss │ │ ├── _bordered-pulled.scss │ │ ├── _core.scss │ │ ├── _fixed-width.scss │ │ ├── _icons.scss │ │ ├── _larger.scss │ │ ├── _list.scss │ │ ├── _mixins.scss │ │ ├── _path.scss │ │ ├── _rotated-flipped.scss │ │ ├── _screen-reader.scss │ │ ├── _stacked.scss │ │ ├── _variables.scss │ │ └── font-awesome.scss │ ├── jquery-easing │ ├── jquery.easing.compatibility.js │ ├── jquery.easing.js │ └── jquery.easing.min.js │ └── jquery │ ├── jquery.js │ └── jquery.min.js └── test └── java └── org └── audit4j └── microservice └── SmokeTest.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.jar 8 | *.war 9 | *.ear 10 | 11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 12 | hs_err_pid* 13 | /target/ 14 | .vertx/ 15 | .settings/ 16 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | audit4j-microservice 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.m2e.core.maven2Builder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.m2e.core.maven2Nature 22 | 23 | 24 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 3 | org.eclipse.jdt.core.compiler.compliance=1.8 4 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 5 | org.eclipse.jdt.core.compiler.source=1.8 6 | -------------------------------------------------------------------------------- /.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Audit4j build and test via Travis-CI 2 | 3 | language: java 4 | 5 | jdk: 6 | - oraclejdk8 7 | 8 | script: mvn clean install -DskipTests=true -Dgpg.skip=true 9 | 10 | notifications: 11 | email: 12 | recipients: 13 | - janith@audit4j.org -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | Audit4j microservice is developed to fix following limitations in [Audit4j Core](https://github.com/audit4j/audit4j-core). 4 | 5 | 1. Audit4j core is not supported to embed in applications developed other than Java. 6 | 2. Audit4j core is not suitable for component based enterprise applications (Ex: SOA) which required to store Audit logs in a central location. 7 | 8 | # Getting Started 9 | 10 | ## Prerequisites 11 | You need the following installed and available in your $PATH: 12 | 13 | * Java 8 (http://java.oracle.com) 14 | * Apache maven 3.0.4 or greater (http://maven.apache.org/) 15 | 16 | ## Build 17 | 18 | Execute below two maven goals. 19 | 20 | ```mvn clean package``` 21 | 22 | ```mvn assembly:single``` 23 | 24 | ## Run the microservice 25 | 26 | 1. Copy and extract `audit4j-microservice-1.0.0-distribution.tar.gz` under `target` directory 27 | 2. Go to bin directory 28 | 3. execute `start.bat` 29 | 30 | Dashboard: http://localhost:8080 31 | 32 | ### Default Ports 33 | * 8080 - Dashboard and REST api 34 | * 9091 - WebSocket transport 35 | * 9092 - RPC transport 36 | 37 | ### Configurations 38 | Configurations files are located in conf directory, [Audit4j core configurations](http://audit4j.org/documentation/#configuration) and Server configurations are served as seperately. 39 | 40 | ## Client Api 41 | We have developed client api consists of two types of transports for various requirements. 42 | 43 | ### RPC transport 44 | RPC transport is the fastest transport and the protocol is consists of binary and compressed messages. The transport is developed on top of Apache thrift which added out-of-the-box support for various [languages](https://thrift.apache.org/docs/Languages). 45 | 46 | #### Basic Configurations 47 | 48 | conf/server.config.yml 49 | 50 | ```yml 51 | !ServerConfiguration 52 | transports: 53 | - !org.audit4j.microservice.transport.thrift.ThriftTransportServer 54 | serverPort = 9999 #server port set to 9999 Default 9092 55 | serverHost = localhost 56 | multiThreadded = true #Server to initialize as multithreadded server default is single threadded. 57 | 58 | ``` 59 | #### Genarating client stub 60 | 61 | 1. [Download and install](https://thrift.apache.org/docs/install/) Apache Thrift Compiler. 62 | 2. Copy Audit4j microservice [api](https://github.com/audit4j/audit4j-microservice/blob/master/api/api.thrift) to a desired location. 63 | 3. Generate client stub using below command. 64 | 65 | ```thrift --gen api.thrift``` 66 | 67 | #### SSL Configurations 68 | 69 | Securing Audit traffic is only recommended if the traffic is exposed as a public service. Using below steps, RPC communication can be secured via SSL. 70 | 71 | 1. Creating key store for server 72 | ```keytool -genkeypair -alias certificatekey -keyalg RSA -validity 7 -keystore keystore.jks``` 73 | 74 | 2. Export certificate 75 | ```keytool -export -alias certificatekey -keystore keystore.jks -rfc -file cert.cer``` 76 | 77 | 3. Creating trust store for client 78 | ```keytool -import -alias certificatekey -file cert.cer -keystore truststore.jks``` 79 | 80 | 4. Configure RPC transport 81 | 82 | ```yml 83 | !ServerConfiguration 84 | transports: 85 | - !org.audit4j.microservice.transport.thrift.ThriftTransportServer 86 | secureServer = true 87 | secureKeyStore = conf/trust/keystore.jks 88 | secureKeyPassword = 123456 #Given password while creating the keystore 89 | ``` 90 | 91 | ### Web Socket transport 92 | 93 | 94 | # Support 95 | The following methods are available to obtain support: 96 | 97 | - [The Audit4j Google Group](https://groups.google.com/forum/#!forum/audit4j) - This would normally be your first stop to get support for Audit4j. Here you can find previously asked question, and ask new ones. When asking a question, please provide as much information as you can regarding the environment you use (development language, library, versions. 98 | - The [Issues tab](https://github.com/audit4j/audit4j-microservice/issues) - Please open feature requests and bugs here. If you're not sure you encountered a bug, or if it's a general usage question, please use the Google Group mentioned above. 99 | 100 | 101 | -------------------------------------------------------------------------------- /api/api.thrift: -------------------------------------------------------------------------------- 1 | namespace java org.audit4j.microservice.transport.thrift 2 | 3 | 4 | typedef i32 int; 5 | typedef i64 long; 6 | typedef string Timestamp; 7 | 8 | struct TEventMeta { 9 | 1: string client, 10 | } 11 | 12 | struct TField { 13 | 1: string name, 14 | 2: string value, 15 | 3: string type, 16 | } 17 | 18 | typedef list Fields; 19 | 20 | struct TAuditEvent { 21 | 1: long uuid, 22 | 2: Timestamp timestamp, 23 | 3: string timestampFormat, 24 | 4: optional TEventMeta meta, 25 | 5: string action, 26 | 6: optional string actor, 27 | 7: optional string origin, 28 | 8: optional string tag, 29 | 9: optional string repository, 30 | 10: optional Fields fields, 31 | } 32 | 33 | struct TAuditEventBatch { 34 | 1. list events 35 | } 36 | 37 | struct TAck { 38 | 1: string message, 39 | 2: int code 40 | } 41 | 42 | service TAuditService { 43 | TAck audit(1:TAuditEvent event), 44 | } -------------------------------------------------------------------------------- /assembly/distribution.xml: -------------------------------------------------------------------------------- 1 | 4 | distribution 5 | 6 | tar.gz 7 | zip 8 | 9 | 10 | 11 | ${project.build.directory}/distribution 12 | 13 | lib/* 14 | 15 | / 16 | 17 | 18 | ${basedir} 19 | 20 | bin/* 21 | 22 | / 23 | 24 | 25 | ${basedir} 26 | 27 | conf/* 28 | 29 | / 30 | 31 | 32 | ${basedir} 33 | 34 | lock/* 35 | 36 | / 37 | 38 | 39 | 40 | 41 | 42 | ${project.build.directory}/${artifactId}-${version}.jar 43 | /lib 44 | 45 | 46 | ${basedir}/LICENSE 47 | / 48 | 49 | 50 | ${basedir}/README.md 51 | / 52 | 53 | 54 | -------------------------------------------------------------------------------- /bin/start.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setLocal EnableDelayedExpansion 3 | set CLASSPATH=" 4 | for /R ../ %%a in (*.*) do ( 5 | set CLASSPATH=!CLASSPATH!;%%a 6 | ) 7 | set CLASSPATH=!CLASSPATH!" 8 | 9 | java org.audit4j.microservice.Main -------------------------------------------------------------------------------- /conf/audit4j.conf.yml: -------------------------------------------------------------------------------- 1 | !Configuration 2 | handlers: 3 | - !org.audit4j.core.handler.ConsoleAuditHandler {} 4 | layout: !org.audit4j.core.layout.SimpleLayout {} 5 | metaData: !org.audit4j.core.DummyMetaData {} 6 | properties: 7 | log.file.location: user.dir 8 | -------------------------------------------------------------------------------- /conf/server.config.yml: -------------------------------------------------------------------------------- 1 | !ServerConfiguration 2 | transports: 3 | - !org.audit4j.microservice.transport.thrift.ThriftTransportServer {} #Transport via websocket: Default port 9092 4 | - !org.audit4j.microservice.transport.WebSocketTransportServer {} #Transport via websocket: Default port 9091 5 | -------------------------------------------------------------------------------- /conf/trust/cert.cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDezCCAmOgAwIBAgIEPi50NzANBgkqhkiG9w0BAQsFADBuMQswCQYDVQQGEwJM 3 | SzEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHQ29sb21ibzEQMA4GA1UEChMH 4 | YXVkaXQ0ajEQMA4GA1UECxMHYXVkaXQ0ajEXMBUGA1UEAxMOSmFuaXRoIEJhbmRh 5 | cmEwHhcNMTcxMjI1MTQxNTMzWhcNMTgwMTAxMTQxNTMzWjBuMQswCQYDVQQGEwJM 6 | SzEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHQ29sb21ibzEQMA4GA1UEChMH 7 | YXVkaXQ0ajEQMA4GA1UECxMHYXVkaXQ0ajEXMBUGA1UEAxMOSmFuaXRoIEJhbmRh 8 | cmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgr2tCmAs0JlAbnxNo 9 | TvWTmOzRz9Y0BEIpotQ0sKMumO1joyGMVn2cIKVzOrMYQh9bOtLmS3VhWe8l6zNh 10 | dGivL6RcVrmSDXH6ODE9AYa+StKhSuLXtHVfAzT2gQNVjBRsMB1ECq/ZuPxDWsDi 11 | G/mtofsrM/taQWTSYqSodLW58ZFqv88PD0UpYzm0KSdN8xItUDrL70p7W/fpLkI0 12 | cvT1bMYu4JbZ7ABUShbVfsuXZEm8D5YUGPpvBPw297vl/EDqPHN3QtLEfKBXCQnM 13 | eTX8G9Tw6c4XQIhnUM2POD07mTKS39Th+FAeHEXKQpJCksJuzagWwpKXfVFGytkN 14 | UcBzAgMBAAGjITAfMB0GA1UdDgQWBBS5tz+E2aRoBGJ7v+cZPCGdEBMc8TANBgkq 15 | hkiG9w0BAQsFAAOCAQEAah1nYSnFVGzLt2a8sQpf2XTu9G5qFj7Ly4NELaeIHFVc 16 | NoeGORFga6UybytUOmtFUaKRuzxJ0Hy7wzb0Y35lLAJdlUTXl2Z6EycN/WeQLjAv 17 | V1FToxhhje3viMYuvg/IBrr6ECidjYOt70xjBSIM+9MeKO542tXTaBMWGlv+Fxfz 18 | DJw2Mrs2dHZ5mK1cHxP6iaasmEX6l5OlE1hk4qsCWWasEOF3ybkRmZV/akK7jXc9 19 | AmFeJh799tMZccWq5yOk1mCP52BQJiYtsPooWBby1Cb6Z/qaodosZHyqmhx+N3es 20 | 7sIHMpV5XttMGBILWNNKmR84QGXJxawRWuOJ6FY5Wg== 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /conf/trust/keystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audit4j/audit4j-microservice/eed7a9999a84706a3b649e3f78d3ff13af1a1cd8/conf/trust/keystore.jks -------------------------------------------------------------------------------- /conf/trust/truststore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audit4j/audit4j-microservice/eed7a9999a84706a3b649e3f78d3ff13af1a1cd8/conf/trust/truststore.jks -------------------------------------------------------------------------------- /lock/server.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audit4j/audit4j-microservice/eed7a9999a84706a3b649e3f78d3ff13af1a1cd8/lock/server.lock -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | org.audit4j 5 | audit4j-microservice 6 | jar 7 | Audit4j - Microservice 8 | 1.0.0 9 | http://audit4j.org 10 | Audit4j - An open-source auditing framework for Java, Microservice 11 | 12 | Audit4j 13 | http://audit4j.org 14 | 15 | 16 | 17 | The Apache Software License, Version 2.0 18 | http://www.apache.org/licenses/LICENSE-2.0.txt 19 | repo 20 | 21 | 22 | 23 | 24 | 25 | janith 26 | Janith Bandara 27 | Audit4j 28 | http://audit4j.org 29 | janith@audit4j.org 30 | 31 | owner 32 | developer 33 | 34 | +05:30 35 | 36 | 37 | 38 | 39 | 2.5.0 40 | 0.8.15 41 | 42 | 43 | 44 | 45 | log4j 46 | log4j 47 | 1.2.17 48 | 49 | 50 | org.slf4j 51 | slf4j-log4j12 52 | 1.7.13 53 | 54 | 55 | junit 56 | junit 57 | 4.11 58 | test 59 | 60 | 61 | org.mockito 62 | mockito-core 63 | 1.10.19 64 | test 65 | 66 | 67 | 68 | 69 | org.audit4j 70 | audit4j-core 71 | 2.6.0 72 | 73 | 74 | 75 | 76 | io.vertx 77 | vertx-core 78 | 3.1.0 79 | 80 | 81 | io.vertx 82 | vertx-web 83 | 3.1.0 84 | 85 | 86 | 87 | com.google.code.gson 88 | gson 89 | 2.5 90 | 91 | 92 | 93 | de.ruedigermoeller 94 | fst 95 | 2.42 96 | 97 | 98 | 99 | com.eaio.uuid 100 | uuid 101 | 3.2 102 | 103 | 104 | 105 | org.apache.thrift 106 | libthrift 107 | 0.10.0 108 | 109 | 110 | 111 | 112 | 113 | 114 | org.apache.maven.plugins 115 | maven-compiler-plugin 116 | 117 | 1.8 118 | 1.8 119 | 120 | 121 | 122 | org.apache.maven.plugins 123 | maven-jar-plugin 124 | 125 | 126 | 127 | true 128 | org.audit4j.microservice.Main 129 | 130 | 131 | 132 | 133 | 134 | org.apache.maven.plugins 135 | maven-dependency-plugin 136 | 3.0.2 137 | 138 | 139 | copy-dependencies 140 | package 141 | 142 | copy-dependencies 143 | 144 | 145 | ${project.build.directory}/distribution/lib 146 | false 147 | false 148 | true 149 | compile 150 | 151 | 152 | 153 | 154 | 155 | maven-assembly-plugin 156 | 3.1.0 157 | 158 | 159 | assembly/distribution.xml 160 | 161 | 162 | 163 | 164 | 165 | org.apache.maven.plugins 166 | maven-javadoc-plugin 167 | 168 | 169 | attach-javadocs 170 | 171 | install 172 | 173 | jar 174 | 175 | 176 | 177 | 178 | 179 | org.apache.maven.plugins 180 | maven-source-plugin 181 | 182 | 183 | install 184 | 185 | jar 186 | 187 | 188 | 189 | 190 | 191 | org.apache.maven.plugins 192 | maven-release-plugin 193 | 2.5 194 | 195 | v@{project.version} 196 | 197 | 198 | 199 | org.apache.maven.plugins 200 | maven-eclipse-plugin 201 | 202 | 203 | org.apache.maven.plugins 204 | maven-surefire-plugin 205 | 206 | 207 | org.apache.maven.plugins 208 | maven-gpg-plugin 209 | 210 | 211 | sign-artifacts 212 | verify 213 | 214 | sign 215 | 216 | 217 | 218 | 219 | 220 | 221 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/AppRunningChecker.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.RandomAccessFile; 6 | import java.nio.channels.FileChannel; 7 | import java.nio.channels.FileLock; 8 | 9 | public class AppRunningChecker { 10 | 11 | static File file; 12 | static FileChannel fileChannel; 13 | static FileLock lock; 14 | static boolean running = false; 15 | 16 | @SuppressWarnings("resource") 17 | public static boolean checkIfAlreadyRunning() throws IOException { 18 | file = new File("../lock/"+ "server.lock"); 19 | if (!file.exists()) { 20 | file.createNewFile(); 21 | running = true; 22 | } else { 23 | file.delete(); 24 | } 25 | 26 | fileChannel = new RandomAccessFile(file, "rw").getChannel(); 27 | lock = fileChannel.tryLock(); 28 | 29 | if (lock == null) { 30 | fileChannel.close(); 31 | return true; 32 | } 33 | 34 | return running; 35 | } 36 | 37 | public static void unlockFile() { 38 | try { 39 | if (lock != null) 40 | lock.release(); 41 | fileChannel.close(); 42 | file.delete(); 43 | running = false; 44 | } catch (IOException e) { 45 | e.printStackTrace(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/Main.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice; 2 | 3 | import java.util.Scanner; 4 | 5 | public class Main { 6 | 7 | public static void main(String[] args) { 8 | Main main = new Main(); 9 | main.run(args); 10 | } 11 | 12 | public void run(String[] args) { 13 | ServerContext server = new ServerContext(); 14 | server.start(); 15 | 16 | Scanner sc = new Scanner(System.in); 17 | if (sc.hasNextLine()) { 18 | String line = sc.nextLine(); 19 | if ("exit".equals(line)) { 20 | server.stop(); 21 | System.exit(0); 22 | } 23 | } 24 | 25 | Runtime.getRuntime().addShutdownHook(new Thread(() -> { 26 | server.stop(); 27 | })); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/ServerConfiguration.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import org.audit4j.microservice.core.Configuration; 8 | import org.audit4j.microservice.core.Transport; 9 | 10 | public class ServerConfiguration extends Configuration { 11 | 12 | private List transports = new ArrayList<>(); 13 | 14 | public List getTransports() { 15 | return transports; 16 | } 17 | 18 | public void setTransports(List transports) { 19 | this.transports = transports; 20 | } 21 | 22 | @Override 23 | public String toString() { 24 | return "ServerConfiguration [transports=" + transports + "]"; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/ServerContext.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice; 2 | 3 | import java.io.IOException; 4 | 5 | import org.audit4j.core.AuditManager; 6 | import org.audit4j.core.exception.ConfigurationException; 7 | import org.audit4j.core.exception.InitializationException; 8 | import org.audit4j.microservice.core.ConfigurationManager; 9 | import org.audit4j.microservice.core.Context; 10 | import org.audit4j.microservice.core.HTTPServer; 11 | import org.audit4j.microservice.core.Transport; 12 | 13 | class ServerContext implements Context { 14 | 15 | private String serverConfigFilePath = "../conf/server.config.yml"; 16 | 17 | private String audit4jConfigFilePath = "../conf/audit4j.conf.yml"; 18 | 19 | private ServerConfiguration config; 20 | 21 | HTTPServer httpServer = HTTPServer.create(8080); 22 | 23 | @Override 24 | public void start() throws InitializationException { 25 | System.out.println("===================================================="); 26 | System.out.println("========= Starting Audit4j Microservice... ========="); 27 | System.out.println("===================================================="); 28 | 29 | try { 30 | if (AppRunningChecker.checkIfAlreadyRunning()) { 31 | System.out.println("An instance is already running...!"); 32 | System.exit(0); 33 | } 34 | } catch (IOException e1) { 35 | // TODO Auto-generated catch block 36 | e1.printStackTrace(); 37 | } 38 | 39 | // Load Configurations 40 | ConfigurationManager manager = new ConfigurationManager(serverConfigFilePath); 41 | try { 42 | config = manager.loadConfiguration(); 43 | System.out.println("CONF: " + config); 44 | } catch (ConfigurationException e) { 45 | throw new InitializationException("Could not load configuraiton.!", e); 46 | } 47 | 48 | // Initializing transports 49 | for (Transport transport : config.getTransports()) { 50 | transport.init(); 51 | } 52 | 53 | // Initializing HTTP Server 54 | 55 | httpServer.init(); 56 | 57 | // Initialize Audit4j Core 58 | AuditManager.startWithConfiguration(audit4jConfigFilePath); 59 | 60 | System.out.println("===================================================="); 61 | System.out.println("========== Audit4j Microservice Started.! =========="); 62 | System.out.println("===================================================="); 63 | System.out.println("type: 'exit' to shutdown server safetly."); 64 | } 65 | 66 | @Override 67 | public void stop() { 68 | for (Transport transport : config.getTransports()) { 69 | transport.stop(); 70 | } 71 | 72 | httpServer.stop(); 73 | 74 | AuditManager.shutdown(); 75 | // AppRunningChecker.unlockFile(); 76 | 77 | System.out.println("===================================================="); 78 | System.out.println("===== Audit4j Microservice shutdown safetly.! ======"); 79 | System.out.println("===================================================="); 80 | } 81 | 82 | @Override 83 | public void enable() { 84 | // TODO Auto-generated method stub 85 | 86 | } 87 | 88 | @Override 89 | public void disable() { 90 | // TODO Auto-generated method stub 91 | 92 | } 93 | 94 | @Override 95 | public void terminate() { 96 | // TODO Auto-generated method stub 97 | 98 | } 99 | 100 | void setServerConfigFilePath(String serverConfigFilePath) { 101 | this.serverConfigFilePath = serverConfigFilePath; 102 | } 103 | 104 | void setAudit4jConfigFilePath(String audit4jConfigFilePath) { 105 | this.audit4jConfigFilePath = audit4jConfigFilePath; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/core/Ack.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.core; 2 | 3 | import java.io.Serializable; 4 | 5 | public class Ack implements Serializable{ 6 | 7 | /** 8 | * 9 | */ 10 | private static final long serialVersionUID = -8707468501787579530L; 11 | 12 | private String message; 13 | 14 | private int code; 15 | 16 | public String getMessage() { 17 | return message; 18 | } 19 | 20 | public void setMessage(String message) { 21 | this.message = message; 22 | } 23 | 24 | public int getCode() { 25 | return code; 26 | } 27 | 28 | public void setCode(int code) { 29 | this.code = code; 30 | } 31 | 32 | public static Ack SUCCESS(){ 33 | Ack ack = new Ack(); 34 | ack.setCode(200); 35 | ack.setMessage("success"); 36 | return ack; 37 | } 38 | 39 | public static Ack FAIL(){ 40 | Ack ack = new Ack(); 41 | ack.setCode(500); 42 | ack.setMessage("fail"); 43 | return ack; 44 | } 45 | 46 | public static Ack UNAUTHORIZED(){ 47 | Ack ack = new Ack(); 48 | ack.setCode(401); 49 | ack.setMessage("unauthorized"); 50 | return ack; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/core/Configuration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | */ 4 | package org.audit4j.microservice.core; 5 | 6 | import java.util.Map; 7 | 8 | /** 9 | * The Class Configuration. 10 | */ 11 | public class Configuration { 12 | 13 | /** The properties. */ 14 | private Map properties; 15 | 16 | /** 17 | * Gets the properties. 18 | * 19 | * @return the properties 20 | */ 21 | public Map getProperties() { 22 | return properties; 23 | } 24 | 25 | /** 26 | * Sets the properties. 27 | * 28 | * @param properties the properties 29 | */ 30 | public void setProperties(Map properties) { 31 | this.properties = properties; 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return "Configuration [properties=" + properties + "]"; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/core/ConfigurationManager.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.core; 2 | 3 | import java.io.InputStream; 4 | 5 | import org.audit4j.core.ConfigProvider; 6 | import org.audit4j.core.Configurations; 7 | import org.audit4j.core.YAMLConfigProvider; 8 | import org.audit4j.core.exception.ConfigurationException; 9 | import org.audit4j.core.util.ClassLoaderUtils; 10 | import org.audit4j.microservice.ServerConfiguration; 11 | 12 | public class ConfigurationManager { 13 | 14 | private ConfigProvider configProvider; 15 | 16 | private String configPath = "conf/server.config.yml"; 17 | 18 | public ConfigurationManager(String configPath) { 19 | this.configPath = configPath; 20 | configProvider = new YAMLConfigProvider<>(ServerConfiguration.class); 21 | } 22 | 23 | public ServerConfiguration loadConfiguration() throws ConfigurationException { 24 | ServerConfiguration config = null; 25 | config = configProvider 26 | .readConfig(configPath); 27 | return config; 28 | } 29 | 30 | static InputStream getClasspathResourceAsStream(String resourceName) { 31 | return ClassLoaderUtils.getClassLoader(Configurations.class) 32 | .getResourceAsStream(resourceName); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/core/Context.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.core; 2 | 3 | import org.audit4j.core.exception.InitializationException; 4 | 5 | public interface Context { 6 | 7 | void start() throws InitializationException; 8 | 9 | void stop(); 10 | 11 | void enable(); 12 | 13 | void disable(); 14 | 15 | void terminate(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/core/ContextAware.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.core; 2 | 3 | import org.audit4j.core.Initializable; 4 | 5 | public interface ContextAware { 6 | 7 | public void setContext(T context); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/core/EventReceiver.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.core; 2 | 3 | import org.audit4j.core.dto.AuditEvent; 4 | 5 | public interface EventReceiver { 6 | 7 | Ack receive(AuditEvent event); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/core/EventReceiverImpl.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.core; 2 | 3 | import org.audit4j.core.AuditManager; 4 | import org.audit4j.core.dto.AuditEvent; 5 | 6 | public class EventReceiverImpl implements EventReceiver { 7 | @Override 8 | public Ack receive(AuditEvent event) { 9 | /*// Validate Event 10 | if (clientContext.containsClient(event.getMeta().client)) { 11 | AuditManager.getInstance().audit(event); 12 | return Ack.SUCCESS(); 13 | } else { 14 | return Ack.UNAUTHORIZED(); 15 | }*/ 16 | 17 | AuditManager.getInstance().audit(event); 18 | return Ack.SUCCESS(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/core/HTTPServer.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.core; 2 | 3 | import org.audit4j.core.Initializable; 4 | import org.audit4j.microservice.web.VertxServer; 5 | 6 | public interface HTTPServer extends Initializable{ 7 | 8 | void setPort(int port); 9 | 10 | public static HTTPServer create(int port) { 11 | return new VertxServer(port); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/core/Transport.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.core; 2 | 3 | import java.util.Map; 4 | 5 | import org.audit4j.core.Initializable; 6 | import org.audit4j.core.dto.AuditEvent; 7 | 8 | /** 9 | * The Class Transport. 10 | */ 11 | public abstract class Transport implements Initializable { 12 | 13 | /** The reciever. */ 14 | EventReceiver reciever = new EventReceiverImpl(); 15 | 16 | /** The properties. */ 17 | private Map properties; 18 | 19 | /** 20 | * Receive. 21 | * 22 | * @param event the event 23 | */ 24 | public void receive(AuditEvent event) { 25 | reciever.receive(event); 26 | } 27 | 28 | /** 29 | * Gets the property. 30 | * 31 | * @param key the key 32 | * @return the property 33 | */ 34 | public String getProperty(String key) { 35 | return properties.get(key); 36 | } 37 | 38 | /** 39 | * Sets the properties. 40 | * 41 | * @param properties the properties 42 | */ 43 | public void setProperties(final Map properties) { 44 | this.properties = properties; 45 | } 46 | 47 | public EventReceiver getReciever() { 48 | return reciever; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/transport/AuditServerHandler.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.transport; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import org.audit4j.core.dto.AuditEvent; 6 | import org.audit4j.core.dto.Event; 7 | import org.audit4j.core.dto.EventBatch; 8 | import org.audit4j.core.exception.HandlerException; 9 | import org.audit4j.core.exception.InitializationException; 10 | import org.audit4j.core.handler.Handler; 11 | import org.nustaq.serialization.FSTConfiguration; 12 | 13 | import io.vertx.core.Vertx; 14 | import io.vertx.core.http.HttpClient; 15 | 16 | public class AuditServerHandler extends Handler { 17 | 18 | /** 19 | * 20 | */ 21 | private static final long serialVersionUID = -4367445636079624061L; 22 | private FSTConfiguration conf; 23 | private WebsocketHandler handler = null; 24 | private HttpClient client; 25 | private Vertx vertx; 26 | private Integer port = 9999; 27 | 28 | private String host = "localhost"; 29 | 30 | @Override 31 | public void init() throws InitializationException { 32 | handler = new WebsocketHandler(); 33 | handler.init(); 34 | conf = FSTConfiguration.createDefaultConfiguration(); 35 | vertx = Vertx.vertx(); 36 | client = vertx.createHttpClient(); 37 | client.websocket(port, host, "/audit", handler); 38 | } 39 | 40 | @Override 41 | public void handle() throws HandlerException { 42 | handler.sendBinary(conf.asByteArray(getAuditEvent())); 43 | } 44 | 45 | @Override 46 | public void stop() { 47 | handler.stop(); 48 | client.close(); 49 | vertx.close(); 50 | } 51 | 52 | public static void main(String[] args) throws Exception { 53 | AuditServerHandler client = new AuditServerHandler<>(); 54 | client.init(); 55 | 56 | TimeUnit.SECONDS.sleep(5); 57 | for (int i = 0; i < 500; i++) { 58 | AuditEvent event = new AuditEvent(); 59 | event.setClient("03a1c230-d1fa-11e5-9758-68f728daf525"); 60 | event.setAction("asdsa" + i); 61 | event.setActor("asdas"); 62 | client.setAuditEvent(event); 63 | client.handle(); 64 | } 65 | } 66 | 67 | @Override 68 | public void handle(String formattedEvent) throws HandlerException { 69 | // TODO Auto-generated method stub 70 | 71 | } 72 | 73 | @Override 74 | public void handle(AuditEvent event) throws HandlerException { 75 | // TODO Auto-generated method stub 76 | 77 | } 78 | 79 | @Override 80 | public void handle(EventBatch batch) throws HandlerException { 81 | // TODO Auto-generated method stub 82 | 83 | } 84 | 85 | 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/transport/Serializer.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.transport; 2 | 3 | // TODO: Auto-generated Javadoc 4 | /** 5 | * The Interface Serializer. 6 | */ 7 | public interface Serializer { 8 | 9 | /** 10 | * From byte array. 11 | * 12 | * @param the generic type 13 | * @param bytes the bytes 14 | * @param target the target 15 | * @return the t 16 | */ 17 | T fromByteArray(byte[] bytes, Class target); 18 | 19 | /** 20 | * To byte array. 21 | * 22 | * @param object the object 23 | * @return the byte[] 24 | */ 25 | byte[] toByteArray(Object object); 26 | 27 | /** 28 | * From json. 29 | * 30 | * @param the generic type 31 | * @param json the json 32 | * @param target the target 33 | * @return the t 34 | */ 35 | T fromJson(String json, Class target); 36 | 37 | /** 38 | * To json. 39 | * 40 | * @param object the object 41 | * @return the string 42 | */ 43 | String toJson(Object object); 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/transport/SerializerImpl.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.transport; 2 | 3 | import org.nustaq.serialization.FSTConfiguration; 4 | 5 | import com.google.gson.Gson; 6 | 7 | /** 8 | * Custom Serialization Wrapper. 9 | */ 10 | public class SerializerImpl implements Serializer { 11 | 12 | /** The conf. */ 13 | private FSTConfiguration conf; 14 | 15 | /** The gson. */ 16 | private Gson gson; 17 | 18 | /** 19 | * Instantiates a new serializer. 20 | */ 21 | public SerializerImpl() { 22 | conf = FSTConfiguration.createDefaultConfiguration(); 23 | gson = new Gson(); 24 | } 25 | 26 | /** 27 | * As object. 28 | * 29 | * @param 30 | * the generic type 31 | * @param bytes 32 | * the bytes 33 | * @param target 34 | * the target 35 | * @return the t 36 | */ 37 | @Override 38 | @SuppressWarnings("unchecked") 39 | public T fromByteArray(byte[] bytes, Class target) { 40 | return (T) conf.asObject(bytes); 41 | } 42 | 43 | /** 44 | * As byte array. 45 | * 46 | * @param object 47 | * the object 48 | * @return the byte[] 49 | */ 50 | @Override 51 | public byte[] toByteArray(Object object) { 52 | return conf.asByteArray(object); 53 | } 54 | 55 | /* 56 | * (non-Javadoc) 57 | * 58 | * @see 59 | * org.audit4j.microservice.transport.Serializer#fromJson(java.lang.String, 60 | * java.lang.Class) 61 | */ 62 | @Override 63 | public T fromJson(String json, Class target) { 64 | return gson.fromJson(json, target); 65 | } 66 | 67 | /* 68 | * (non-Javadoc) 69 | * 70 | * @see 71 | * org.audit4j.microservice.transport.Serializer#toJson(java.lang.Object) 72 | */ 73 | @Override 74 | public String toJson(Object object) { 75 | return gson.toJson(object); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/transport/WebSocketTransportServer.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.transport; 2 | 3 | import org.audit4j.core.dto.AuditEvent; 4 | import org.audit4j.core.exception.InitializationException; 5 | import org.audit4j.core.util.Log; 6 | import org.audit4j.microservice.core.Ack; 7 | import org.audit4j.microservice.core.Transport; 8 | 9 | import io.vertx.core.Vertx; 10 | import io.vertx.core.buffer.Buffer; 11 | 12 | public class WebSocketTransportServer extends Transport { 13 | 14 | Serializer serializer; 15 | 16 | private int port = 9091; 17 | 18 | @Override 19 | public void init() throws InitializationException { 20 | 21 | serializer = new SerializerImpl(); 22 | 23 | // VertxOptions options = new VertxOptions(); 24 | Vertx vertx = Vertx.vertx(); 25 | 26 | vertx.createHttpServer() 27 | .websocketHandler( 28 | ws -> ws.handler(buffer -> { 29 | ws.frameHandler(event -> { 30 | if (event.isFinal()) { 31 | if (event.isBinary()) { 32 | byte[] buff = buffer.getBytes(); 33 | try { 34 | AuditEvent auditEvent = serializer 35 | .fromByteArray(buff, 36 | AuditEvent.class); 37 | 38 | Log.info("Recived Message.."); 39 | ws.writeBinaryMessage(Buffer.buffer(serializer 40 | .toByteArray(Ack.SUCCESS()))); 41 | receive(auditEvent); 42 | } catch (Exception e) { 43 | ws.writeBinaryMessage(Buffer 44 | .buffer(serializer 45 | .toByteArray(Ack 46 | .FAIL()))); 47 | } 48 | 49 | } else if (event.isText()) { 50 | AuditEvent auditEvent = serializer.fromJson( 51 | buffer.toString(), 52 | AuditEvent.class); 53 | Log.info("Recived Message.."); 54 | ws.writeFinalTextFrame("success"); 55 | receive(auditEvent); 56 | } 57 | } 58 | 59 | }); 60 | })).listen(port); 61 | System.out.println("Web Socket Transport server started.! port: " + port ); 62 | } 63 | 64 | public void setPort(int port) { 65 | this.port = port; 66 | } 67 | 68 | public void setSerializer(Serializer serializer) { 69 | this.serializer = serializer; 70 | } 71 | 72 | @Override 73 | public void stop() { 74 | // TODO Auto-generated method stub 75 | 76 | } 77 | 78 | public static void main(String[] args) { 79 | WebSocketTransportServer server = new WebSocketTransportServer(); 80 | server.init(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/transport/WebsocketHandler.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.transport; 2 | 3 | import io.vertx.core.Handler; 4 | import io.vertx.core.buffer.Buffer; 5 | import io.vertx.core.http.WebSocket; 6 | 7 | import org.audit4j.core.Initializable; 8 | import org.audit4j.core.exception.InitializationException; 9 | import org.audit4j.microservice.core.Ack; 10 | import org.nustaq.serialization.FSTConfiguration; 11 | 12 | public class WebsocketHandler implements Handler, Initializable{ 13 | FSTConfiguration conf = FSTConfiguration.createDefaultConfiguration(); 14 | 15 | WebSocket websocket; 16 | 17 | @Override 18 | public void handle(WebSocket websocket) { 19 | this.websocket = websocket; 20 | websocket.handler(data -> { 21 | Ack ack = (Ack) conf.asObject(data.getBytes()); 22 | System.out.println(ack.getMessage()); 23 | }); 24 | 25 | //byte eventBytes[] = conf.asByteArray(event); 26 | //websocket.writeBinaryMessage(Buffer.buffer(eventBytes)); 27 | //websocket.close(); 28 | } 29 | 30 | public void sendBinary(byte[] data){ 31 | websocket.writeBinaryMessage(Buffer.buffer(data)); 32 | } 33 | 34 | @Override 35 | public void init() throws InitializationException { 36 | // TODO Auto-generated method stub 37 | 38 | } 39 | 40 | @Override 41 | public void stop() { 42 | websocket.close(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/transport/thrift/TAckTransformer.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.transport.thrift; 2 | 3 | import org.audit4j.microservice.core.Ack; 4 | 5 | public class TAckTransformer { 6 | 7 | public Ack transformToAck(TAck ack) { 8 | Ack auditAck = new Ack(); 9 | auditAck.setCode(ack.getCode()); 10 | auditAck.setMessage(ack.getMessage()); 11 | return auditAck; 12 | } 13 | 14 | public TAck transformFromAck(Ack auditAck) { 15 | TAck ack = new TAck(); 16 | ack.setCode(auditAck.getCode()); 17 | ack.setMessage(auditAck.getMessage()); 18 | return ack; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/transport/thrift/TAuditEventTransformer.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.transport.thrift; 2 | 3 | import java.text.ParseException; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Date; 6 | 7 | import org.audit4j.core.dto.AuditEvent; 8 | import org.audit4j.core.dto.EventMeta; 9 | import org.audit4j.core.dto.Field; 10 | 11 | public class TAuditEventTransformer { 12 | 13 | public AuditEvent transformToEvent(TAuditEvent event) { 14 | AuditEvent auditEvent = new AuditEvent(); 15 | auditEvent.setUuid(event.getUuid()); 16 | 17 | SimpleDateFormat format = new SimpleDateFormat(event.getTimestampFormat()); 18 | Date date = null; 19 | try { 20 | date = format.parse(event.getTimestamp()); 21 | } catch (ParseException e) { 22 | // TODO Auto-generated catch block 23 | e.printStackTrace(); 24 | } 25 | 26 | auditEvent.setTimestamp(date); 27 | auditEvent.setMeta(transformToEventMeta(event.getMeta())); 28 | auditEvent.setAction(event.getAction()); 29 | auditEvent.setActor(event.getActor()); 30 | auditEvent.setOrigin(event.getOrigin()); 31 | auditEvent.setTag(event.getTag()); 32 | auditEvent.setRepository(event.getRepository()); 33 | if (event.getFields() != null) { 34 | for (TField field : event.getFields()) { 35 | auditEvent.addField(transformToField(field)); 36 | } 37 | } 38 | 39 | return auditEvent; 40 | } 41 | 42 | public EventMeta transformToEventMeta(TEventMeta meta) { 43 | if (meta == null) { 44 | return null; 45 | } 46 | EventMeta eventMeta = new EventMeta(); 47 | eventMeta.setClient(meta.getClient()); 48 | return eventMeta; 49 | } 50 | 51 | 52 | public Field transformToField (TField field) { 53 | Field auditField = new Field(); 54 | auditField.setName(field.getName()); 55 | auditField.setValue(field.getValue()); 56 | auditField.setType(field.getType()); 57 | return auditField; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/transport/thrift/TAuditHandler.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.transport.thrift; 2 | 3 | import org.apache.thrift.TException; 4 | import org.audit4j.microservice.core.EventReceiver; 5 | 6 | public class TAuditHandler implements TAuditService.Iface { 7 | 8 | private EventReceiver reciver; 9 | TAuditEventTransformer transformer; 10 | TAckTransformer ackTransformer; 11 | 12 | public TAuditHandler(EventReceiver reciver) { 13 | this.reciver = reciver; 14 | this.transformer = new TAuditEventTransformer(); 15 | this.ackTransformer = new TAckTransformer(); 16 | } 17 | 18 | @Override 19 | public TAck audit(TAuditEvent event) throws TException { 20 | return ackTransformer.transformFromAck(reciver.receive(transformer.transformToEvent(event))); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/transport/thrift/TEventMeta.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Autogenerated by Thrift Compiler (0.11.0) 3 | * 4 | * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING 5 | * @generated 6 | */ 7 | package org.audit4j.microservice.transport.thrift; 8 | 9 | @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) 10 | @javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.11.0)", date = "2017-12-13") 11 | public class TEventMeta implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { 12 | private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("TEventMeta"); 13 | 14 | private static final org.apache.thrift.protocol.TField CLIENT_FIELD_DESC = new org.apache.thrift.protocol.TField("client", org.apache.thrift.protocol.TType.STRING, (short)1); 15 | 16 | private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new TEventMetaStandardSchemeFactory(); 17 | private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new TEventMetaTupleSchemeFactory(); 18 | 19 | public java.lang.String client; // required 20 | 21 | /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ 22 | public enum _Fields implements org.apache.thrift.TFieldIdEnum { 23 | CLIENT((short)1, "client"); 24 | 25 | private static final java.util.Map byName = new java.util.HashMap(); 26 | 27 | static { 28 | for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { 29 | byName.put(field.getFieldName(), field); 30 | } 31 | } 32 | 33 | /** 34 | * Find the _Fields constant that matches fieldId, or null if its not found. 35 | */ 36 | public static _Fields findByThriftId(int fieldId) { 37 | switch(fieldId) { 38 | case 1: // CLIENT 39 | return CLIENT; 40 | default: 41 | return null; 42 | } 43 | } 44 | 45 | /** 46 | * Find the _Fields constant that matches fieldId, throwing an exception 47 | * if it is not found. 48 | */ 49 | public static _Fields findByThriftIdOrThrow(int fieldId) { 50 | _Fields fields = findByThriftId(fieldId); 51 | if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!"); 52 | return fields; 53 | } 54 | 55 | /** 56 | * Find the _Fields constant that matches name, or null if its not found. 57 | */ 58 | public static _Fields findByName(java.lang.String name) { 59 | return byName.get(name); 60 | } 61 | 62 | private final short _thriftId; 63 | private final java.lang.String _fieldName; 64 | 65 | _Fields(short thriftId, java.lang.String fieldName) { 66 | _thriftId = thriftId; 67 | _fieldName = fieldName; 68 | } 69 | 70 | public short getThriftFieldId() { 71 | return _thriftId; 72 | } 73 | 74 | public java.lang.String getFieldName() { 75 | return _fieldName; 76 | } 77 | } 78 | 79 | // isset id assignments 80 | public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; 81 | static { 82 | java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); 83 | tmpMap.put(_Fields.CLIENT, new org.apache.thrift.meta_data.FieldMetaData("client", org.apache.thrift.TFieldRequirementType.DEFAULT, 84 | new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); 85 | metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); 86 | org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(TEventMeta.class, metaDataMap); 87 | } 88 | 89 | public TEventMeta() { 90 | } 91 | 92 | public TEventMeta( 93 | java.lang.String client) 94 | { 95 | this(); 96 | this.client = client; 97 | } 98 | 99 | /** 100 | * Performs a deep copy on other. 101 | */ 102 | public TEventMeta(TEventMeta other) { 103 | if (other.isSetClient()) { 104 | this.client = other.client; 105 | } 106 | } 107 | 108 | public TEventMeta deepCopy() { 109 | return new TEventMeta(this); 110 | } 111 | 112 | @Override 113 | public void clear() { 114 | this.client = null; 115 | } 116 | 117 | public java.lang.String getClient() { 118 | return this.client; 119 | } 120 | 121 | public TEventMeta setClient(java.lang.String client) { 122 | this.client = client; 123 | return this; 124 | } 125 | 126 | public void unsetClient() { 127 | this.client = null; 128 | } 129 | 130 | /** Returns true if field client is set (has been assigned a value) and false otherwise */ 131 | public boolean isSetClient() { 132 | return this.client != null; 133 | } 134 | 135 | public void setClientIsSet(boolean value) { 136 | if (!value) { 137 | this.client = null; 138 | } 139 | } 140 | 141 | public void setFieldValue(_Fields field, java.lang.Object value) { 142 | switch (field) { 143 | case CLIENT: 144 | if (value == null) { 145 | unsetClient(); 146 | } else { 147 | setClient((java.lang.String)value); 148 | } 149 | break; 150 | 151 | } 152 | } 153 | 154 | public java.lang.Object getFieldValue(_Fields field) { 155 | switch (field) { 156 | case CLIENT: 157 | return getClient(); 158 | 159 | } 160 | throw new java.lang.IllegalStateException(); 161 | } 162 | 163 | /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ 164 | public boolean isSet(_Fields field) { 165 | if (field == null) { 166 | throw new java.lang.IllegalArgumentException(); 167 | } 168 | 169 | switch (field) { 170 | case CLIENT: 171 | return isSetClient(); 172 | } 173 | throw new java.lang.IllegalStateException(); 174 | } 175 | 176 | @Override 177 | public boolean equals(java.lang.Object that) { 178 | if (that == null) 179 | return false; 180 | if (that instanceof TEventMeta) 181 | return this.equals((TEventMeta)that); 182 | return false; 183 | } 184 | 185 | public boolean equals(TEventMeta that) { 186 | if (that == null) 187 | return false; 188 | if (this == that) 189 | return true; 190 | 191 | boolean this_present_client = true && this.isSetClient(); 192 | boolean that_present_client = true && that.isSetClient(); 193 | if (this_present_client || that_present_client) { 194 | if (!(this_present_client && that_present_client)) 195 | return false; 196 | if (!this.client.equals(that.client)) 197 | return false; 198 | } 199 | 200 | return true; 201 | } 202 | 203 | @Override 204 | public int hashCode() { 205 | int hashCode = 1; 206 | 207 | hashCode = hashCode * 8191 + ((isSetClient()) ? 131071 : 524287); 208 | if (isSetClient()) 209 | hashCode = hashCode * 8191 + client.hashCode(); 210 | 211 | return hashCode; 212 | } 213 | 214 | @Override 215 | public int compareTo(TEventMeta other) { 216 | if (!getClass().equals(other.getClass())) { 217 | return getClass().getName().compareTo(other.getClass().getName()); 218 | } 219 | 220 | int lastComparison = 0; 221 | 222 | lastComparison = java.lang.Boolean.valueOf(isSetClient()).compareTo(other.isSetClient()); 223 | if (lastComparison != 0) { 224 | return lastComparison; 225 | } 226 | if (isSetClient()) { 227 | lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.client, other.client); 228 | if (lastComparison != 0) { 229 | return lastComparison; 230 | } 231 | } 232 | return 0; 233 | } 234 | 235 | public _Fields fieldForId(int fieldId) { 236 | return _Fields.findByThriftId(fieldId); 237 | } 238 | 239 | public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { 240 | scheme(iprot).read(iprot, this); 241 | } 242 | 243 | public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { 244 | scheme(oprot).write(oprot, this); 245 | } 246 | 247 | @Override 248 | public java.lang.String toString() { 249 | java.lang.StringBuilder sb = new java.lang.StringBuilder("TEventMeta("); 250 | boolean first = true; 251 | 252 | sb.append("client:"); 253 | if (this.client == null) { 254 | sb.append("null"); 255 | } else { 256 | sb.append(this.client); 257 | } 258 | first = false; 259 | sb.append(")"); 260 | return sb.toString(); 261 | } 262 | 263 | public void validate() throws org.apache.thrift.TException { 264 | // check for required fields 265 | // check for sub-struct validity 266 | } 267 | 268 | private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { 269 | try { 270 | write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); 271 | } catch (org.apache.thrift.TException te) { 272 | throw new java.io.IOException(te); 273 | } 274 | } 275 | 276 | private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException { 277 | try { 278 | read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); 279 | } catch (org.apache.thrift.TException te) { 280 | throw new java.io.IOException(te); 281 | } 282 | } 283 | 284 | private static class TEventMetaStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { 285 | public TEventMetaStandardScheme getScheme() { 286 | return new TEventMetaStandardScheme(); 287 | } 288 | } 289 | 290 | private static class TEventMetaStandardScheme extends org.apache.thrift.scheme.StandardScheme { 291 | 292 | public void read(org.apache.thrift.protocol.TProtocol iprot, TEventMeta struct) throws org.apache.thrift.TException { 293 | org.apache.thrift.protocol.TField schemeField; 294 | iprot.readStructBegin(); 295 | while (true) 296 | { 297 | schemeField = iprot.readFieldBegin(); 298 | if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 299 | break; 300 | } 301 | switch (schemeField.id) { 302 | case 1: // CLIENT 303 | if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { 304 | struct.client = iprot.readString(); 305 | struct.setClientIsSet(true); 306 | } else { 307 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 308 | } 309 | break; 310 | default: 311 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 312 | } 313 | iprot.readFieldEnd(); 314 | } 315 | iprot.readStructEnd(); 316 | 317 | // check for required fields of primitive type, which can't be checked in the validate method 318 | struct.validate(); 319 | } 320 | 321 | public void write(org.apache.thrift.protocol.TProtocol oprot, TEventMeta struct) throws org.apache.thrift.TException { 322 | struct.validate(); 323 | 324 | oprot.writeStructBegin(STRUCT_DESC); 325 | if (struct.client != null) { 326 | oprot.writeFieldBegin(CLIENT_FIELD_DESC); 327 | oprot.writeString(struct.client); 328 | oprot.writeFieldEnd(); 329 | } 330 | oprot.writeFieldStop(); 331 | oprot.writeStructEnd(); 332 | } 333 | 334 | } 335 | 336 | private static class TEventMetaTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { 337 | public TEventMetaTupleScheme getScheme() { 338 | return new TEventMetaTupleScheme(); 339 | } 340 | } 341 | 342 | private static class TEventMetaTupleScheme extends org.apache.thrift.scheme.TupleScheme { 343 | 344 | @Override 345 | public void write(org.apache.thrift.protocol.TProtocol prot, TEventMeta struct) throws org.apache.thrift.TException { 346 | org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; 347 | java.util.BitSet optionals = new java.util.BitSet(); 348 | if (struct.isSetClient()) { 349 | optionals.set(0); 350 | } 351 | oprot.writeBitSet(optionals, 1); 352 | if (struct.isSetClient()) { 353 | oprot.writeString(struct.client); 354 | } 355 | } 356 | 357 | @Override 358 | public void read(org.apache.thrift.protocol.TProtocol prot, TEventMeta struct) throws org.apache.thrift.TException { 359 | org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; 360 | java.util.BitSet incoming = iprot.readBitSet(1); 361 | if (incoming.get(0)) { 362 | struct.client = iprot.readString(); 363 | struct.setClientIsSet(true); 364 | } 365 | } 366 | } 367 | 368 | private static S scheme(org.apache.thrift.protocol.TProtocol proto) { 369 | return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); 370 | } 371 | } 372 | 373 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/transport/thrift/ThriftTransportServer.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.transport.thrift; 2 | 3 | import java.net.InetAddress; 4 | import java.net.InetSocketAddress; 5 | 6 | import org.apache.thrift.server.TServer; 7 | import org.apache.thrift.server.TServer.Args; 8 | import org.apache.thrift.server.TSimpleServer; 9 | import org.apache.thrift.server.TThreadPoolServer; 10 | import org.apache.thrift.transport.TSSLTransportFactory; 11 | import org.apache.thrift.transport.TSSLTransportFactory.TSSLTransportParameters; 12 | import org.apache.thrift.transport.TServerSocket; 13 | import org.apache.thrift.transport.TServerTransport; 14 | import org.audit4j.core.exception.InitializationException; 15 | import org.audit4j.microservice.core.Transport; 16 | 17 | public class ThriftTransportServer extends Transport { 18 | 19 | public static TAuditHandler handler; 20 | 21 | public static TAuditService.Processor processor; 22 | 23 | private TServer tServer; 24 | 25 | private int serverPort = 9092; 26 | 27 | private String serverHost = "localhost"; 28 | 29 | private String secureKeyStore; 30 | 31 | private String secureKeyPassword; 32 | 33 | private boolean multiThreadded = false; 34 | 35 | boolean secureServer = false; 36 | 37 | public ThriftTransportServer() {} 38 | 39 | public ThriftTransportServer(String host, int port, boolean multiThreadded) { 40 | this.serverHost = host; 41 | this.serverPort = port; 42 | this.multiThreadded = multiThreadded; 43 | } 44 | 45 | public ThriftTransportServer(String host, int port, boolean multiThreadded, String keyStore, String keyPassword) { 46 | this.serverHost = host; 47 | this.serverPort = port; 48 | this.multiThreadded = multiThreadded; 49 | this.secureKeyStore = keyStore; 50 | this.secureKeyPassword = keyPassword; 51 | secureServer = true; 52 | } 53 | 54 | @Override 55 | public void init() throws InitializationException { 56 | try { 57 | handler = new TAuditHandler(getReciever()); 58 | processor = new TAuditService.Processor(handler); 59 | 60 | 61 | Runnable server = new Runnable() { 62 | public void run() { 63 | if (secureServer) { 64 | secure(processor); 65 | } else { 66 | simple(processor); 67 | } 68 | 69 | } 70 | }; 71 | 72 | new Thread(server).start(); 73 | } catch (Exception x) { 74 | x.printStackTrace(); 75 | } 76 | } 77 | 78 | @Override 79 | public void stop() { 80 | tServer.stop(); 81 | } 82 | 83 | public void simple(TAuditService.Processor processor) { 84 | try { 85 | TServerTransport serverTransport = new TServerSocket(new InetSocketAddress(serverHost, serverPort)); 86 | tServer = new TSimpleServer(new Args(serverTransport).processor(processor)); 87 | 88 | System.out.println("Simple RPC server started.! port: " + serverPort ); 89 | tServer.serve(); 90 | } catch (Exception e) { 91 | e.printStackTrace(); 92 | } 93 | } 94 | 95 | public void secure(TAuditService.Processor processor) { 96 | try { 97 | TSSLTransportParameters params = new TSSLTransportParameters(); 98 | // The Keystore contains the private key 99 | params.setKeyStore(secureKeyStore, secureKeyPassword, null, null); 100 | 101 | TServerTransport serverTransport = TSSLTransportFactory.getServerSocket(serverPort, 0, 102 | InetAddress.getByName(serverHost), params); 103 | 104 | // Use this for a multi threaded server 105 | if (multiThreadded) { 106 | tServer = new TThreadPoolServer( 107 | new TThreadPoolServer.Args(serverTransport).processor(processor)); 108 | } else { 109 | tServer = new TSimpleServer(new Args(serverTransport).processor(processor)); 110 | } 111 | 112 | tServer.serve(); 113 | System.out.println("Secure RPC server started.! port: " + serverPort ); 114 | } catch (Exception e) { 115 | e.printStackTrace(); 116 | } 117 | } 118 | 119 | public void setServerPort(int serverPort) { 120 | this.serverPort = serverPort; 121 | } 122 | 123 | public void setServerHost(String serverHost) { 124 | this.serverHost = serverHost; 125 | } 126 | 127 | public void setSecureKeyStore(String secureKeyStore) { 128 | this.secureKeyStore = secureKeyStore; 129 | } 130 | 131 | public void setSecureKeyPassword(String secureKeyPassword) { 132 | this.secureKeyPassword = secureKeyPassword; 133 | } 134 | 135 | public void setMultiThreadded(boolean multiThreadded) { 136 | this.multiThreadded = multiThreadded; 137 | } 138 | 139 | public void setSecureServer(boolean secureServer) { 140 | this.secureServer = secureServer; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/util/KeyGenerator.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.util; 2 | 3 | import com.eaio.uuid.UUID; 4 | 5 | public class KeyGenerator { 6 | 7 | public String generateRandomKey(){ 8 | UUID uuid = new UUID(); 9 | return uuid.toString(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/web/CustomAuth.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.web; 2 | 3 | import org.audit4j.microservice.ServerConfiguration; 4 | 5 | import io.vertx.core.Vertx; 6 | import io.vertx.ext.auth.AuthProvider; 7 | 8 | public interface CustomAuth extends AuthProvider{ 9 | 10 | static CustomAuth create(Vertx vertx, ServerConfiguration config) { 11 | return new CustomAuthImpl(vertx, config); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/web/CustomAuthImpl.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.web; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.audit4j.microservice.ServerConfiguration; 7 | 8 | import io.vertx.core.AsyncResult; 9 | import io.vertx.core.Future; 10 | import io.vertx.core.Handler; 11 | import io.vertx.core.Vertx; 12 | import io.vertx.core.json.JsonObject; 13 | import io.vertx.ext.auth.User; 14 | 15 | public class CustomAuthImpl implements CustomAuth { 16 | 17 | Map users = new HashMap<>(); 18 | 19 | public CustomAuthImpl(Vertx vertx, ServerConfiguration config) { 20 | users.put("test", "123"); 21 | } 22 | 23 | @Override 24 | public void authenticate(JsonObject authInfo, Handler> resultHandler) { 25 | String username = authInfo.getString("username"); 26 | 27 | // Null or empty username is invalid 28 | if (username == null || username.length() == 0) { 29 | resultHandler.handle((Future.failedFuture("Username must be set for authentication."))); 30 | return; 31 | } 32 | 33 | if (!users.containsKey(username)) { 34 | resultHandler.handle((Future.failedFuture("Unknown username."))); 35 | return; 36 | } 37 | final String password = users.get(username); 38 | 39 | if (authInfo.getString("password").equals(password)) { 40 | resultHandler.handle(Future.succeededFuture(new CustomUser(username))); 41 | } else { 42 | resultHandler.handle(Future.failedFuture("Unknown password")); 43 | } 44 | 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/web/CustomUser.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.web; 2 | 3 | import io.vertx.core.AsyncResult; 4 | import io.vertx.core.Future; 5 | import io.vertx.core.Handler; 6 | import io.vertx.core.json.JsonObject; 7 | import io.vertx.ext.auth.AuthProvider; 8 | import io.vertx.ext.auth.User; 9 | 10 | public class CustomUser implements User{ 11 | private String username; 12 | 13 | public CustomUser(String username) { 14 | this.username = username; 15 | } 16 | @Override 17 | public User clearCache() { 18 | return this; 19 | } 20 | 21 | @Override 22 | public User isAuthorised(String authority, Handler> resultHandler) { 23 | resultHandler.handle(Future.succeededFuture(false)); 24 | return this; 25 | } 26 | 27 | @Override 28 | public JsonObject principal() { 29 | return new JsonObject() 30 | .put("username", username); 31 | } 32 | 33 | @Override 34 | public void setAuthProvider(AuthProvider arg0) { 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/web/VertxServer.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.web; 2 | 3 | import org.audit4j.core.exception.InitializationException; 4 | import org.audit4j.microservice.core.HTTPServer; 5 | import org.audit4j.microservice.web.rest.RestRouter; 6 | 7 | import io.vertx.core.AbstractVerticle; 8 | import io.vertx.core.Vertx; 9 | import io.vertx.ext.web.Router; 10 | import io.vertx.ext.web.handler.StaticHandler; 11 | 12 | public class VertxServer extends AbstractVerticle implements HTTPServer{ 13 | 14 | private int port; 15 | 16 | Vertx vertx; 17 | 18 | public VertxServer(int port) { 19 | this.port = port; 20 | } 21 | 22 | @Override 23 | public void start() { 24 | WebRouter webRouter = new WebRouter(vertx); 25 | Router router = webRouter.getRouter(); 26 | 27 | RestRouter restRouter = new RestRouter(vertx); 28 | router.mountSubRouter("/api", restRouter.getRouter()); 29 | 30 | 31 | router.route("/*").handler(StaticHandler.create()); 32 | 33 | vertx.createHttpServer().requestHandler(router::accept).listen(port); 34 | } 35 | 36 | 37 | 38 | public static void main(String[] args) { 39 | VertxServer server = new VertxServer(8080); 40 | server.vertx = Vertx.vertx(); 41 | server.vertx.deployVerticle(server); 42 | } 43 | 44 | @Override 45 | public void init() throws InitializationException { 46 | vertx = Vertx.vertx(); 47 | vertx.deployVerticle(this); 48 | System.out.println("Vertx HTTP server started.! port: " + port); 49 | } 50 | 51 | @Override 52 | public void stop() { 53 | vertx.close(); 54 | } 55 | 56 | @Override 57 | public void setPort(int port) { 58 | this.port = port; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/web/WebRouter.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.web; 2 | 3 | import org.audit4j.microservice.ServerConfiguration; 4 | 5 | import io.vertx.core.Vertx; 6 | import io.vertx.ext.auth.AuthProvider; 7 | import io.vertx.ext.web.Router; 8 | import io.vertx.ext.web.handler.BodyHandler; 9 | import io.vertx.ext.web.handler.CookieHandler; 10 | import io.vertx.ext.web.handler.FormLoginHandler; 11 | import io.vertx.ext.web.handler.RedirectAuthHandler; 12 | import io.vertx.ext.web.handler.SessionHandler; 13 | import io.vertx.ext.web.handler.UserSessionHandler; 14 | import io.vertx.ext.web.sstore.LocalSessionStore; 15 | 16 | public class WebRouter { 17 | 18 | Vertx vertx; 19 | 20 | public WebRouter(Vertx vertx) { 21 | this.vertx = vertx; 22 | } 23 | 24 | public Router getRouter() { 25 | Router router = Router.router(vertx); 26 | 27 | // We need cookies, sessions and request bodies 28 | router.route().handler(CookieHandler.create()); 29 | router.route().handler(BodyHandler.create()); 30 | router.route().handler(SessionHandler.create(LocalSessionStore.create(vertx))); 31 | 32 | AuthProvider authProvider = CustomAuth.create(vertx, new ServerConfiguration()); 33 | 34 | router.route().handler(UserSessionHandler.create(authProvider)); 35 | 36 | router.route("/dashboard/*").handler(RedirectAuthHandler.create(authProvider, "/login.html")); 37 | 38 | router.route("/loginhandler").handler(FormLoginHandler.create(authProvider)); 39 | 40 | 41 | // Implement logout 42 | router.route("/logout").handler(context -> { 43 | context.clearUser(); 44 | // Redirect back to the index page 45 | context.response().putHeader("location", "/").setStatusCode(302).end(); 46 | }); 47 | 48 | 49 | return router; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/web/rest/RESTAuditEventHandler.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.web.rest; 2 | 3 | import org.audit4j.core.dto.AuditEvent; 4 | import org.audit4j.microservice.core.Ack; 5 | import org.audit4j.microservice.core.EventReceiver; 6 | import org.audit4j.microservice.core.EventReceiverImpl; 7 | 8 | import io.vertx.core.http.HttpServerResponse; 9 | import io.vertx.core.json.Json; 10 | import io.vertx.core.json.JsonObject; 11 | import io.vertx.ext.web.RoutingContext; 12 | 13 | public class RESTAuditEventHandler { 14 | 15 | private EventReceiver reciever = new EventReceiverImpl(); 16 | 17 | public void handleEvent(RoutingContext routingContext) { 18 | JsonObject jsonEvent = routingContext.getBodyAsJson(); 19 | AuditEvent event = Json.decodeValue(jsonEvent.encode(), AuditEvent.class); 20 | reciever.receive(event); 21 | 22 | HttpServerResponse response = routingContext.response(); 23 | response.putHeader("content-type", "application/json") 24 | .end(new JsonObject(Json.encode(Ack.SUCCESS())).encodePrettily()); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/audit4j/microservice/web/rest/RestRouter.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice.web.rest; 2 | 3 | import io.vertx.core.Vertx; 4 | import io.vertx.core.http.HttpServerResponse; 5 | import io.vertx.core.json.JsonObject; 6 | import io.vertx.ext.web.Router; 7 | import io.vertx.ext.web.RoutingContext; 8 | 9 | public class RestRouter { 10 | 11 | Vertx vertx; 12 | 13 | public RestRouter(Vertx vertx) { 14 | this.vertx = vertx; 15 | } 16 | 17 | public Router getRouter() { 18 | Router router = Router.router(vertx); 19 | 20 | router.get("/health").handler(this::handlerHealth); 21 | router.post("/rest/event").handler(new RESTAuditEventHandler()::handleEvent); 22 | 23 | return router; 24 | } 25 | 26 | private void handlerHealth(RoutingContext routingContext) { 27 | HttpServerResponse response = routingContext.response(); 28 | response.putHeader("content-type", "application/json") 29 | .end(new JsonObject().put("status", "running").encodePrettily()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/main/resources/webroot/css/sb-admin.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Start Bootstrap - SB Admin v4.0.0-beta.2 (https://startbootstrap.com/template-overviews/sb-admin) 3 | * Copyright 2013-2017 Start Bootstrap 4 | * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap-sb-admin/blob/master/LICENSE) 5 | */ 6 | html { 7 | position: relative; 8 | min-height: 100%; } 9 | 10 | body { 11 | overflow-x: hidden; } 12 | 13 | body.sticky-footer { 14 | margin-bottom: 56px; } 15 | body.sticky-footer .content-wrapper { 16 | min-height: calc(100vh - 56px - 56px); } 17 | 18 | body.fixed-nav { 19 | padding-top: 56px; } 20 | 21 | .content-wrapper { 22 | min-height: calc(100vh - 56px); 23 | padding-top: 1rem; } 24 | 25 | .scroll-to-top { 26 | position: fixed; 27 | right: 15px; 28 | bottom: 3px; 29 | display: none; 30 | width: 50px; 31 | height: 50px; 32 | text-align: center; 33 | color: white; 34 | background: rgba(52, 58, 64, 0.5); 35 | line-height: 45px; } 36 | .scroll-to-top:focus, .scroll-to-top:hover { 37 | color: white; } 38 | .scroll-to-top:hover { 39 | background: #343a40; } 40 | .scroll-to-top i { 41 | font-weight: 800; } 42 | 43 | .smaller { 44 | font-size: 0.7rem; } 45 | 46 | .o-hidden { 47 | overflow: hidden !important; } 48 | 49 | .z-0 { 50 | z-index: 0; } 51 | 52 | .z-1 { 53 | z-index: 1; } 54 | 55 | #mainNav .navbar-collapse { 56 | overflow: auto; 57 | max-height: 75vh; } 58 | #mainNav .navbar-collapse .navbar-nav .nav-item .nav-link { 59 | cursor: pointer; } 60 | #mainNav .navbar-collapse .navbar-sidenav .nav-link-collapse:after { 61 | float: right; 62 | content: '\f107'; 63 | font-family: 'FontAwesome'; } 64 | #mainNav .navbar-collapse .navbar-sidenav .nav-link-collapse.collapsed:after { 65 | content: '\f105'; } 66 | #mainNav .navbar-collapse .navbar-sidenav .sidenav-second-level, 67 | #mainNav .navbar-collapse .navbar-sidenav .sidenav-third-level { 68 | padding-left: 0; } 69 | #mainNav .navbar-collapse .navbar-sidenav .sidenav-second-level > li > a, 70 | #mainNav .navbar-collapse .navbar-sidenav .sidenav-third-level > li > a { 71 | display: block; 72 | padding: 0.5em 0; } 73 | #mainNav .navbar-collapse .navbar-sidenav .sidenav-second-level > li > a:focus, #mainNav .navbar-collapse .navbar-sidenav .sidenav-second-level > li > a:hover, 74 | #mainNav .navbar-collapse .navbar-sidenav .sidenav-third-level > li > a:focus, 75 | #mainNav .navbar-collapse .navbar-sidenav .sidenav-third-level > li > a:hover { 76 | text-decoration: none; } 77 | #mainNav .navbar-collapse .navbar-sidenav .sidenav-second-level > li > a { 78 | padding-left: 1em; } 79 | #mainNav .navbar-collapse .navbar-sidenav .sidenav-third-level > li > a { 80 | padding-left: 2em; } 81 | #mainNav .navbar-collapse .sidenav-toggler { 82 | display: none; } 83 | #mainNav .navbar-collapse .navbar-nav > .nav-item.dropdown > .nav-link { 84 | position: relative; 85 | min-width: 45px; } 86 | #mainNav .navbar-collapse .navbar-nav > .nav-item.dropdown > .nav-link:after { 87 | float: right; 88 | width: auto; 89 | content: '\f105'; 90 | border: none; 91 | font-family: 'FontAwesome'; } 92 | #mainNav .navbar-collapse .navbar-nav > .nav-item.dropdown > .nav-link .indicator { 93 | position: absolute; 94 | top: 5px; 95 | left: 21px; 96 | font-size: 10px; } 97 | #mainNav .navbar-collapse .navbar-nav > .nav-item.dropdown.show > .nav-link:after { 98 | content: '\f107'; } 99 | #mainNav .navbar-collapse .navbar-nav > .nav-item.dropdown .dropdown-menu > .dropdown-item > .dropdown-message { 100 | overflow: hidden; 101 | max-width: none; 102 | text-overflow: ellipsis; } 103 | 104 | @media (min-width: 992px) { 105 | #mainNav .navbar-brand { 106 | width: 250px; } 107 | #mainNav .navbar-collapse { 108 | overflow: visible; 109 | max-height: none; } 110 | #mainNav .navbar-collapse .navbar-sidenav { 111 | position: absolute; 112 | top: 0; 113 | left: 0; 114 | overflow-x: hidden; 115 | overflow-y: auto; 116 | -webkit-flex-direction: column; 117 | -ms-flex-direction: column; 118 | flex-direction: column; 119 | margin-top: 56px; } 120 | #mainNav .navbar-collapse .navbar-sidenav > .nav-item { 121 | width: 250px; 122 | padding: 0; } 123 | #mainNav .navbar-collapse .navbar-sidenav > .nav-item > .nav-link { 124 | padding: 1em; } 125 | #mainNav .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level, 126 | #mainNav .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level { 127 | padding-left: 0; 128 | list-style: none; } 129 | #mainNav .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level > li, 130 | #mainNav .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level > li { 131 | width: 250px; } 132 | #mainNav .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level > li > a, 133 | #mainNav .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level > li > a { 134 | padding: 1em; } 135 | #mainNav .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level > li > a { 136 | padding-left: 2.75em; } 137 | #mainNav .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level > li > a { 138 | padding-left: 3.75em; } 139 | #mainNav .navbar-collapse .navbar-nav > .nav-item.dropdown > .nav-link { 140 | min-width: 0; } 141 | #mainNav .navbar-collapse .navbar-nav > .nav-item.dropdown > .nav-link:after { 142 | width: 24px; 143 | text-align: center; } 144 | #mainNav .navbar-collapse .navbar-nav > .nav-item.dropdown .dropdown-menu > .dropdown-item > .dropdown-message { 145 | max-width: 300px; } } 146 | 147 | #mainNav.fixed-top .sidenav-toggler { 148 | display: none; } 149 | 150 | @media (min-width: 992px) { 151 | #mainNav.fixed-top .navbar-sidenav { 152 | height: calc(100vh - 112px); } 153 | #mainNav.fixed-top .sidenav-toggler { 154 | position: absolute; 155 | top: 0; 156 | left: 0; 157 | display: flex; 158 | overflow-x: hidden; 159 | overflow-y: auto; 160 | -webkit-flex-direction: column; 161 | -ms-flex-direction: column; 162 | flex-direction: column; 163 | margin-top: calc(100vh - 56px); } 164 | #mainNav.fixed-top .sidenav-toggler > .nav-item { 165 | width: 250px; 166 | padding: 0; } 167 | #mainNav.fixed-top .sidenav-toggler > .nav-item > .nav-link { 168 | padding: 1em; } } 169 | 170 | #mainNav.fixed-top.navbar-dark .sidenav-toggler { 171 | background-color: #212529; } 172 | #mainNav.fixed-top.navbar-dark .sidenav-toggler a i { 173 | color: #adb5bd; } 174 | 175 | #mainNav.fixed-top.navbar-light .sidenav-toggler { 176 | background-color: #dee2e6; } 177 | #mainNav.fixed-top.navbar-light .sidenav-toggler a i { 178 | color: rgba(0, 0, 0, 0.5); } 179 | 180 | body.sidenav-toggled #mainNav.fixed-top .sidenav-toggler { 181 | overflow-x: hidden; 182 | width: 55px; } 183 | body.sidenav-toggled #mainNav.fixed-top .sidenav-toggler .nav-item, 184 | body.sidenav-toggled #mainNav.fixed-top .sidenav-toggler .nav-link { 185 | width: 55px !important; } 186 | 187 | body.sidenav-toggled #mainNav.fixed-top #sidenavToggler i { 188 | -webkit-transform: scaleX(-1); 189 | -moz-transform: scaleX(-1); 190 | -o-transform: scaleX(-1); 191 | transform: scaleX(-1); 192 | filter: FlipH; 193 | -ms-filter: 'FlipH'; } 194 | 195 | #mainNav.static-top .sidenav-toggler { 196 | display: none; } 197 | 198 | @media (min-width: 992px) { 199 | #mainNav.static-top .sidenav-toggler { 200 | display: flex; } } 201 | 202 | body.sidenav-toggled #mainNav.static-top #sidenavToggler i { 203 | -webkit-transform: scaleX(-1); 204 | -moz-transform: scaleX(-1); 205 | -o-transform: scaleX(-1); 206 | transform: scaleX(-1); 207 | filter: FlipH; 208 | -ms-filter: 'FlipH'; } 209 | 210 | .content-wrapper { 211 | overflow-x: hidden; 212 | background: white; } 213 | @media (min-width: 992px) { 214 | .content-wrapper { 215 | margin-left: 250px; } } 216 | 217 | #sidenavToggler i { 218 | font-weight: 800; } 219 | 220 | .navbar-sidenav-tooltip.show { 221 | display: none; } 222 | 223 | @media (min-width: 992px) { 224 | body.sidenav-toggled .content-wrapper { 225 | margin-left: 55px; } } 226 | 227 | body.sidenav-toggled .navbar-sidenav { 228 | overflow-x: hidden; 229 | width: 55px; } 230 | body.sidenav-toggled .navbar-sidenav .nav-link-text { 231 | display: none; } 232 | body.sidenav-toggled .navbar-sidenav .nav-item, 233 | body.sidenav-toggled .navbar-sidenav .nav-link { 234 | width: 55px !important; } 235 | body.sidenav-toggled .navbar-sidenav .nav-item:after, 236 | body.sidenav-toggled .navbar-sidenav .nav-link:after { 237 | display: none; } 238 | 239 | body.sidenav-toggled .navbar-sidenav-tooltip.show { 240 | display: flex; } 241 | 242 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav .nav-link-collapse:after { 243 | color: #868e96; } 244 | 245 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav > .nav-item > .nav-link { 246 | color: #868e96; } 247 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav > .nav-item > .nav-link:hover { 248 | color: #adb5bd; } 249 | 250 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level > li > a, 251 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level > li > a { 252 | color: #868e96; } 253 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level > li > a:focus, #mainNav.navbar-dark .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level > li > a:hover, 254 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level > li > a:focus, 255 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level > li > a:hover { 256 | color: #adb5bd; } 257 | 258 | #mainNav.navbar-dark .navbar-collapse .navbar-nav > .nav-item.dropdown > .nav-link:after { 259 | color: #adb5bd; } 260 | 261 | @media (min-width: 992px) { 262 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav { 263 | background: #343a40; } 264 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav li.active a { 265 | color: white !important; 266 | background-color: #495057; } 267 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav li.active a:focus, #mainNav.navbar-dark .navbar-collapse .navbar-sidenav li.active a:hover { 268 | color: white; } 269 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level, 270 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level { 271 | background: #343a40; } } 272 | 273 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav .nav-link-collapse:after { 274 | color: rgba(0, 0, 0, 0.5); } 275 | 276 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav > .nav-item > .nav-link { 277 | color: rgba(0, 0, 0, 0.5); } 278 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav > .nav-item > .nav-link:hover { 279 | color: rgba(0, 0, 0, 0.7); } 280 | 281 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level > li > a, 282 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level > li > a { 283 | color: rgba(0, 0, 0, 0.5); } 284 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level > li > a:focus, #mainNav.navbar-light .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level > li > a:hover, 285 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level > li > a:focus, 286 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level > li > a:hover { 287 | color: rgba(0, 0, 0, 0.7); } 288 | 289 | #mainNav.navbar-light .navbar-collapse .navbar-nav > .nav-item.dropdown > .nav-link:after { 290 | color: rgba(0, 0, 0, 0.5); } 291 | 292 | @media (min-width: 992px) { 293 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav { 294 | background: #f8f9fa; } 295 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav li.active a { 296 | color: #000 !important; 297 | background-color: #e9ecef; } 298 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav li.active a:focus, #mainNav.navbar-light .navbar-collapse .navbar-sidenav li.active a:hover { 299 | color: #000; } 300 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level, 301 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level { 302 | background: #f8f9fa; } } 303 | 304 | .card-body-icon { 305 | position: absolute; 306 | z-index: 0; 307 | top: -25px; 308 | right: -25px; 309 | font-size: 5rem; 310 | -webkit-transform: rotate(15deg); 311 | -ms-transform: rotate(15deg); 312 | transform: rotate(15deg); } 313 | 314 | @media (min-width: 576px) { 315 | .card-columns { 316 | column-count: 1; } } 317 | 318 | @media (min-width: 768px) { 319 | .card-columns { 320 | column-count: 2; } } 321 | 322 | @media (min-width: 1200px) { 323 | .card-columns { 324 | column-count: 2; } } 325 | 326 | .card-login { 327 | max-width: 25rem; } 328 | 329 | .card-register { 330 | max-width: 40rem; } 331 | 332 | footer.sticky-footer { 333 | position: absolute; 334 | right: 0; 335 | bottom: 0; 336 | width: 100%; 337 | height: 56px; 338 | background-color: #e9ecef; 339 | line-height: 55px; } 340 | @media (min-width: 992px) { 341 | footer.sticky-footer { 342 | width: calc(100% - 250px); } } 343 | 344 | @media (min-width: 992px) { 345 | body.sidenav-toggled footer.sticky-footer { 346 | width: calc(100% - 55px); } } 347 | -------------------------------------------------------------------------------- /src/main/resources/webroot/css/sb-admin.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Start Bootstrap - SB Admin v4.0.0-beta.2 (https://startbootstrap.com/template-overviews/sb-admin) 3 | * Copyright 2013-2017 Start Bootstrap 4 | * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap-sb-admin/blob/master/LICENSE) 5 | */html{position:relative;min-height:100%}body{overflow-x:hidden}body.sticky-footer{margin-bottom:56px}body.sticky-footer .content-wrapper{min-height:calc(100vh - 56px - 56px)}body.fixed-nav{padding-top:56px}.content-wrapper{min-height:calc(100vh - 56px);padding-top:1rem}.scroll-to-top{position:fixed;right:15px;bottom:3px;display:none;width:50px;height:50px;text-align:center;color:#fff;background:rgba(52,58,64,.5);line-height:45px}.scroll-to-top:focus,.scroll-to-top:hover{color:#fff}.scroll-to-top:hover{background:#343a40}.scroll-to-top i{font-weight:800}.smaller{font-size:.7rem}.o-hidden{overflow:hidden!important}.z-0{z-index:0}.z-1{z-index:1}#mainNav .navbar-collapse{overflow:auto;max-height:75vh}#mainNav .navbar-collapse .navbar-nav .nav-item .nav-link{cursor:pointer}#mainNav .navbar-collapse .navbar-sidenav .nav-link-collapse:after{float:right;content:'\f107';font-family:FontAwesome}#mainNav .navbar-collapse .navbar-sidenav .nav-link-collapse.collapsed:after{content:'\f105'}#mainNav .navbar-collapse .navbar-sidenav .sidenav-second-level,#mainNav .navbar-collapse .navbar-sidenav .sidenav-third-level{padding-left:0}#mainNav .navbar-collapse .navbar-sidenav .sidenav-second-level>li>a,#mainNav .navbar-collapse .navbar-sidenav .sidenav-third-level>li>a{display:block;padding:.5em 0}#mainNav .navbar-collapse .navbar-sidenav .sidenav-second-level>li>a:focus,#mainNav .navbar-collapse .navbar-sidenav .sidenav-second-level>li>a:hover,#mainNav .navbar-collapse .navbar-sidenav .sidenav-third-level>li>a:focus,#mainNav .navbar-collapse .navbar-sidenav .sidenav-third-level>li>a:hover{text-decoration:none}#mainNav .navbar-collapse .navbar-sidenav .sidenav-second-level>li>a{padding-left:1em}#mainNav .navbar-collapse .navbar-sidenav .sidenav-third-level>li>a{padding-left:2em}#mainNav .navbar-collapse .sidenav-toggler{display:none}#mainNav .navbar-collapse .navbar-nav>.nav-item.dropdown>.nav-link{position:relative;min-width:45px}#mainNav .navbar-collapse .navbar-nav>.nav-item.dropdown>.nav-link:after{float:right;width:auto;content:'\f105';border:none;font-family:FontAwesome}#mainNav .navbar-collapse .navbar-nav>.nav-item.dropdown>.nav-link .indicator{position:absolute;top:5px;left:21px;font-size:10px}#mainNav .navbar-collapse .navbar-nav>.nav-item.dropdown.show>.nav-link:after{content:'\f107'}#mainNav .navbar-collapse .navbar-nav>.nav-item.dropdown .dropdown-menu>.dropdown-item>.dropdown-message{overflow:hidden;max-width:none;text-overflow:ellipsis}@media (min-width:992px){#mainNav .navbar-brand{width:250px}#mainNav .navbar-collapse{overflow:visible;max-height:none}#mainNav .navbar-collapse .navbar-sidenav{position:absolute;top:0;left:0;overflow-x:hidden;overflow-y:auto;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;margin-top:56px}#mainNav .navbar-collapse .navbar-sidenav>.nav-item{width:250px;padding:0}#mainNav .navbar-collapse .navbar-sidenav>.nav-item>.nav-link{padding:1em}#mainNav .navbar-collapse .navbar-sidenav>.nav-item .sidenav-second-level,#mainNav .navbar-collapse .navbar-sidenav>.nav-item .sidenav-third-level{padding-left:0;list-style:none}#mainNav .navbar-collapse .navbar-sidenav>.nav-item .sidenav-second-level>li,#mainNav .navbar-collapse .navbar-sidenav>.nav-item .sidenav-third-level>li{width:250px}#mainNav .navbar-collapse .navbar-sidenav>.nav-item .sidenav-second-level>li>a,#mainNav .navbar-collapse .navbar-sidenav>.nav-item .sidenav-third-level>li>a{padding:1em}#mainNav .navbar-collapse .navbar-sidenav>.nav-item .sidenav-second-level>li>a{padding-left:2.75em}#mainNav .navbar-collapse .navbar-sidenav>.nav-item .sidenav-third-level>li>a{padding-left:3.75em}#mainNav .navbar-collapse .navbar-nav>.nav-item.dropdown>.nav-link{min-width:0}#mainNav .navbar-collapse .navbar-nav>.nav-item.dropdown>.nav-link:after{width:24px;text-align:center}#mainNav .navbar-collapse .navbar-nav>.nav-item.dropdown .dropdown-menu>.dropdown-item>.dropdown-message{max-width:300px}}#mainNav.fixed-top .sidenav-toggler{display:none}@media (min-width:992px){#mainNav.fixed-top .navbar-sidenav{height:calc(100vh - 112px)}#mainNav.fixed-top .sidenav-toggler{position:absolute;top:0;left:0;display:flex;overflow-x:hidden;overflow-y:auto;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;margin-top:calc(100vh - 56px)}#mainNav.fixed-top .sidenav-toggler>.nav-item{width:250px;padding:0}#mainNav.fixed-top .sidenav-toggler>.nav-item>.nav-link{padding:1em}}#mainNav.fixed-top.navbar-dark .sidenav-toggler{background-color:#212529}#mainNav.fixed-top.navbar-dark .sidenav-toggler a i{color:#adb5bd}#mainNav.fixed-top.navbar-light .sidenav-toggler{background-color:#dee2e6}#mainNav.fixed-top.navbar-light .sidenav-toggler a i{color:rgba(0,0,0,.5)}body.sidenav-toggled #mainNav.fixed-top .sidenav-toggler{overflow-x:hidden;width:55px}body.sidenav-toggled #mainNav.fixed-top .sidenav-toggler .nav-item,body.sidenav-toggled #mainNav.fixed-top .sidenav-toggler .nav-link{width:55px!important}body.sidenav-toggled #mainNav.fixed-top #sidenavToggler i{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1);filter:FlipH;-ms-filter:FlipH}#mainNav.static-top .sidenav-toggler{display:none}@media (min-width:992px){#mainNav.static-top .sidenav-toggler{display:flex}}body.sidenav-toggled #mainNav.static-top #sidenavToggler i{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1);filter:FlipH;-ms-filter:FlipH}.content-wrapper{overflow-x:hidden;background:#fff}@media (min-width:992px){.content-wrapper{margin-left:250px}}#sidenavToggler i{font-weight:800}.navbar-sidenav-tooltip.show{display:none}@media (min-width:992px){body.sidenav-toggled .content-wrapper{margin-left:55px}}body.sidenav-toggled .navbar-sidenav{overflow-x:hidden;width:55px}body.sidenav-toggled .navbar-sidenav .nav-link-text{display:none}body.sidenav-toggled .navbar-sidenav .nav-item,body.sidenav-toggled .navbar-sidenav .nav-link{width:55px!important}body.sidenav-toggled .navbar-sidenav .nav-item:after,body.sidenav-toggled .navbar-sidenav .nav-link:after{display:none}body.sidenav-toggled .navbar-sidenav-tooltip.show{display:flex}#mainNav.navbar-dark .navbar-collapse .navbar-sidenav .nav-link-collapse:after{color:#868e96}#mainNav.navbar-dark .navbar-collapse .navbar-sidenav>.nav-item>.nav-link{color:#868e96}#mainNav.navbar-dark .navbar-collapse .navbar-sidenav>.nav-item>.nav-link:hover{color:#adb5bd}#mainNav.navbar-dark .navbar-collapse .navbar-sidenav>.nav-item .sidenav-second-level>li>a,#mainNav.navbar-dark .navbar-collapse .navbar-sidenav>.nav-item .sidenav-third-level>li>a{color:#868e96}#mainNav.navbar-dark .navbar-collapse .navbar-sidenav>.nav-item .sidenav-second-level>li>a:focus,#mainNav.navbar-dark .navbar-collapse .navbar-sidenav>.nav-item .sidenav-second-level>li>a:hover,#mainNav.navbar-dark .navbar-collapse .navbar-sidenav>.nav-item .sidenav-third-level>li>a:focus,#mainNav.navbar-dark .navbar-collapse .navbar-sidenav>.nav-item .sidenav-third-level>li>a:hover{color:#adb5bd}#mainNav.navbar-dark .navbar-collapse .navbar-nav>.nav-item.dropdown>.nav-link:after{color:#adb5bd}@media (min-width:992px){#mainNav.navbar-dark .navbar-collapse .navbar-sidenav{background:#343a40}#mainNav.navbar-dark .navbar-collapse .navbar-sidenav li.active a{color:#fff!important;background-color:#495057}#mainNav.navbar-dark .navbar-collapse .navbar-sidenav li.active a:focus,#mainNav.navbar-dark .navbar-collapse .navbar-sidenav li.active a:hover{color:#fff}#mainNav.navbar-dark .navbar-collapse .navbar-sidenav>.nav-item .sidenav-second-level,#mainNav.navbar-dark .navbar-collapse .navbar-sidenav>.nav-item .sidenav-third-level{background:#343a40}}#mainNav.navbar-light .navbar-collapse .navbar-sidenav .nav-link-collapse:after{color:rgba(0,0,0,.5)}#mainNav.navbar-light .navbar-collapse .navbar-sidenav>.nav-item>.nav-link{color:rgba(0,0,0,.5)}#mainNav.navbar-light .navbar-collapse .navbar-sidenav>.nav-item>.nav-link:hover{color:rgba(0,0,0,.7)}#mainNav.navbar-light .navbar-collapse .navbar-sidenav>.nav-item .sidenav-second-level>li>a,#mainNav.navbar-light .navbar-collapse .navbar-sidenav>.nav-item .sidenav-third-level>li>a{color:rgba(0,0,0,.5)}#mainNav.navbar-light .navbar-collapse .navbar-sidenav>.nav-item .sidenav-second-level>li>a:focus,#mainNav.navbar-light .navbar-collapse .navbar-sidenav>.nav-item .sidenav-second-level>li>a:hover,#mainNav.navbar-light .navbar-collapse .navbar-sidenav>.nav-item .sidenav-third-level>li>a:focus,#mainNav.navbar-light .navbar-collapse .navbar-sidenav>.nav-item .sidenav-third-level>li>a:hover{color:rgba(0,0,0,.7)}#mainNav.navbar-light .navbar-collapse .navbar-nav>.nav-item.dropdown>.nav-link:after{color:rgba(0,0,0,.5)}@media (min-width:992px){#mainNav.navbar-light .navbar-collapse .navbar-sidenav{background:#f8f9fa}#mainNav.navbar-light .navbar-collapse .navbar-sidenav li.active a{color:#000!important;background-color:#e9ecef}#mainNav.navbar-light .navbar-collapse .navbar-sidenav li.active a:focus,#mainNav.navbar-light .navbar-collapse .navbar-sidenav li.active a:hover{color:#000}#mainNav.navbar-light .navbar-collapse .navbar-sidenav>.nav-item .sidenav-second-level,#mainNav.navbar-light .navbar-collapse .navbar-sidenav>.nav-item .sidenav-third-level{background:#f8f9fa}}.card-body-icon{position:absolute;z-index:0;top:-25px;right:-25px;font-size:5rem;-webkit-transform:rotate(15deg);-ms-transform:rotate(15deg);transform:rotate(15deg)}@media (min-width:576px){.card-columns{column-count:1}}@media (min-width:768px){.card-columns{column-count:2}}@media (min-width:1200px){.card-columns{column-count:2}}.card-login{max-width:25rem}.card-register{max-width:40rem}footer.sticky-footer{position:absolute;right:0;bottom:0;width:100%;height:56px;background-color:#e9ecef;line-height:55px}@media (min-width:992px){footer.sticky-footer{width:calc(100% - 250px)}}@media (min-width:992px){body.sidenav-toggled footer.sticky-footer{width:calc(100% - 55px)}} -------------------------------------------------------------------------------- /src/main/resources/webroot/dashboard/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Audit4j Microservice - Dashboard 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 71 |
72 |
73 | 74 | 80 | 81 | 82 |
83 | 84 | 85 |
86 |
87 |
88 | Copyright © Janith Bandara 2017 89 |
90 |
91 |
92 | 93 | 94 | 95 | 96 | 97 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 |
129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /src/main/resources/webroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Audit4j Microservice 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |

Audit4j Microservice

22 | 23 | 28 |
29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/main/resources/webroot/js/sb-admin-charts.js: -------------------------------------------------------------------------------- 1 | // Chart.js scripts 2 | // -- Set new default font family and font color to mimic Bootstrap's default styling 3 | Chart.defaults.global.defaultFontFamily = '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif'; 4 | Chart.defaults.global.defaultFontColor = '#292b2c'; 5 | // -- Area Chart Example 6 | var ctx = document.getElementById("myAreaChart"); 7 | var myLineChart = new Chart(ctx, { 8 | type: 'line', 9 | data: { 10 | labels: ["Mar 1", "Mar 2", "Mar 3", "Mar 4", "Mar 5", "Mar 6", "Mar 7", "Mar 8", "Mar 9", "Mar 10", "Mar 11", "Mar 12", "Mar 13"], 11 | datasets: [{ 12 | label: "Sessions", 13 | lineTension: 0.3, 14 | backgroundColor: "rgba(2,117,216,0.2)", 15 | borderColor: "rgba(2,117,216,1)", 16 | pointRadius: 5, 17 | pointBackgroundColor: "rgba(2,117,216,1)", 18 | pointBorderColor: "rgba(255,255,255,0.8)", 19 | pointHoverRadius: 5, 20 | pointHoverBackgroundColor: "rgba(2,117,216,1)", 21 | pointHitRadius: 20, 22 | pointBorderWidth: 2, 23 | data: [10000, 30162, 26263, 18394, 18287, 28682, 31274, 33259, 25849, 24159, 32651, 31984, 38451], 24 | }], 25 | }, 26 | options: { 27 | scales: { 28 | xAxes: [{ 29 | time: { 30 | unit: 'date' 31 | }, 32 | gridLines: { 33 | display: false 34 | }, 35 | ticks: { 36 | maxTicksLimit: 7 37 | } 38 | }], 39 | yAxes: [{ 40 | ticks: { 41 | min: 0, 42 | max: 40000, 43 | maxTicksLimit: 5 44 | }, 45 | gridLines: { 46 | color: "rgba(0, 0, 0, .125)", 47 | } 48 | }], 49 | }, 50 | legend: { 51 | display: false 52 | } 53 | } 54 | }); 55 | // -- Bar Chart Example 56 | var ctx = document.getElementById("myBarChart"); 57 | var myLineChart = new Chart(ctx, { 58 | type: 'bar', 59 | data: { 60 | labels: ["January", "February", "March", "April", "May", "June"], 61 | datasets: [{ 62 | label: "Revenue", 63 | backgroundColor: "rgba(2,117,216,1)", 64 | borderColor: "rgba(2,117,216,1)", 65 | data: [4215, 5312, 6251, 7841, 9821, 14984], 66 | }], 67 | }, 68 | options: { 69 | scales: { 70 | xAxes: [{ 71 | time: { 72 | unit: 'month' 73 | }, 74 | gridLines: { 75 | display: false 76 | }, 77 | ticks: { 78 | maxTicksLimit: 6 79 | } 80 | }], 81 | yAxes: [{ 82 | ticks: { 83 | min: 0, 84 | max: 15000, 85 | maxTicksLimit: 5 86 | }, 87 | gridLines: { 88 | display: true 89 | } 90 | }], 91 | }, 92 | legend: { 93 | display: false 94 | } 95 | } 96 | }); 97 | // -- Pie Chart Example 98 | var ctx = document.getElementById("myPieChart"); 99 | var myPieChart = new Chart(ctx, { 100 | type: 'pie', 101 | data: { 102 | labels: ["Blue", "Red", "Yellow", "Green"], 103 | datasets: [{ 104 | data: [12.21, 15.58, 11.25, 8.32], 105 | backgroundColor: ['#007bff', '#dc3545', '#ffc107', '#28a745'], 106 | }], 107 | }, 108 | }); 109 | -------------------------------------------------------------------------------- /src/main/resources/webroot/js/sb-admin-charts.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Start Bootstrap - SB Admin v4.0.0-beta.2 (https://startbootstrap.com/template-overviews/sb-admin) 3 | * Copyright 2013-2017 Start Bootstrap 4 | * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap-sb-admin/blob/master/LICENSE) 5 | */ 6 | Chart.defaults.global.defaultFontFamily='-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif',Chart.defaults.global.defaultFontColor="#292b2c";var ctx=document.getElementById("myAreaChart"),myLineChart=new Chart(ctx,{type:"line",data:{labels:["Mar 1","Mar 2","Mar 3","Mar 4","Mar 5","Mar 6","Mar 7","Mar 8","Mar 9","Mar 10","Mar 11","Mar 12","Mar 13"],datasets:[{label:"Sessions",lineTension:.3,backgroundColor:"rgba(2,117,216,0.2)",borderColor:"rgba(2,117,216,1)",pointRadius:5,pointBackgroundColor:"rgba(2,117,216,1)",pointBorderColor:"rgba(255,255,255,0.8)",pointHoverRadius:5,pointHoverBackgroundColor:"rgba(2,117,216,1)",pointHitRadius:20,pointBorderWidth:2,data:[1e4,30162,26263,18394,18287,28682,31274,33259,25849,24159,32651,31984,38451]}]},options:{scales:{xAxes:[{time:{unit:"date"},gridLines:{display:!1},ticks:{maxTicksLimit:7}}],yAxes:[{ticks:{min:0,max:4e4,maxTicksLimit:5},gridLines:{color:"rgba(0, 0, 0, .125)"}}]},legend:{display:!1}}}),ctx=document.getElementById("myBarChart"),myLineChart=new Chart(ctx,{type:"bar",data:{labels:["January","February","March","April","May","June"],datasets:[{label:"Revenue",backgroundColor:"rgba(2,117,216,1)",borderColor:"rgba(2,117,216,1)",data:[4215,5312,6251,7841,9821,14984]}]},options:{scales:{xAxes:[{time:{unit:"month"},gridLines:{display:!1},ticks:{maxTicksLimit:6}}],yAxes:[{ticks:{min:0,max:15e3,maxTicksLimit:5},gridLines:{display:!0}}]},legend:{display:!1}}}),ctx=document.getElementById("myPieChart"),myPieChart=new Chart(ctx,{type:"pie",data:{labels:["Blue","Red","Yellow","Green"],datasets:[{data:[12.21,15.58,11.25,8.32],backgroundColor:["#007bff","#dc3545","#ffc107","#28a745"]}]}}); -------------------------------------------------------------------------------- /src/main/resources/webroot/js/sb-admin-datatables.js: -------------------------------------------------------------------------------- 1 | // Call the dataTables jQuery plugin 2 | $(document).ready(function() { 3 | $('#dataTable').DataTable(); 4 | }); 5 | -------------------------------------------------------------------------------- /src/main/resources/webroot/js/sb-admin-datatables.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Start Bootstrap - SB Admin v4.0.0-beta.2 (https://startbootstrap.com/template-overviews/sb-admin) 3 | * Copyright 2013-2017 Start Bootstrap 4 | * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap-sb-admin/blob/master/LICENSE) 5 | */ 6 | $(document).ready(function(){$("#dataTable").DataTable()}); -------------------------------------------------------------------------------- /src/main/resources/webroot/js/sb-admin.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | "use strict"; // Start of use strict 3 | // Configure tooltips for collapsed side navigation 4 | $('.navbar-sidenav [data-toggle="tooltip"]').tooltip({ 5 | template: '' 6 | }) 7 | // Toggle the side navigation 8 | $("#sidenavToggler").click(function(e) { 9 | e.preventDefault(); 10 | $("body").toggleClass("sidenav-toggled"); 11 | $(".navbar-sidenav .nav-link-collapse").addClass("collapsed"); 12 | $(".navbar-sidenav .sidenav-second-level, .navbar-sidenav .sidenav-third-level").removeClass("show"); 13 | }); 14 | // Force the toggled class to be removed when a collapsible nav link is clicked 15 | $(".navbar-sidenav .nav-link-collapse").click(function(e) { 16 | e.preventDefault(); 17 | $("body").removeClass("sidenav-toggled"); 18 | }); 19 | // Prevent the content wrapper from scrolling when the fixed side navigation hovered over 20 | $('body.fixed-nav .navbar-sidenav, body.fixed-nav .sidenav-toggler, body.fixed-nav .navbar-collapse').on('mousewheel DOMMouseScroll', function(e) { 21 | var e0 = e.originalEvent, 22 | delta = e0.wheelDelta || -e0.detail; 23 | this.scrollTop += (delta < 0 ? 1 : -1) * 30; 24 | e.preventDefault(); 25 | }); 26 | // Scroll to top button appear 27 | $(document).scroll(function() { 28 | var scrollDistance = $(this).scrollTop(); 29 | if (scrollDistance > 100) { 30 | $('.scroll-to-top').fadeIn(); 31 | } else { 32 | $('.scroll-to-top').fadeOut(); 33 | } 34 | }); 35 | // Configure tooltips globally 36 | $('[data-toggle="tooltip"]').tooltip() 37 | // Smooth scrolling using jQuery easing 38 | $(document).on('click', 'a.scroll-to-top', function(event) { 39 | var $anchor = $(this); 40 | $('html, body').stop().animate({ 41 | scrollTop: ($($anchor.attr('href')).offset().top) 42 | }, 1000, 'easeInOutExpo'); 43 | event.preventDefault(); 44 | }); 45 | })(jQuery); // End of use strict 46 | -------------------------------------------------------------------------------- /src/main/resources/webroot/js/sb-admin.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Start Bootstrap - SB Admin v4.0.0-beta.2 (https://startbootstrap.com/template-overviews/sb-admin) 3 | * Copyright 2013-2017 Start Bootstrap 4 | * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap-sb-admin/blob/master/LICENSE) 5 | */ 6 | !function(e){"use strict";e('.navbar-sidenav [data-toggle="tooltip"]').tooltip({template:''}),e("#sidenavToggler").click(function(o){o.preventDefault(),e("body").toggleClass("sidenav-toggled"),e(".navbar-sidenav .nav-link-collapse").addClass("collapsed"),e(".navbar-sidenav .sidenav-second-level, .navbar-sidenav .sidenav-third-level").removeClass("show")}),e(".navbar-sidenav .nav-link-collapse").click(function(o){o.preventDefault(),e("body").removeClass("sidenav-toggled")}),e("body.fixed-nav .navbar-sidenav, body.fixed-nav .sidenav-toggler, body.fixed-nav .navbar-collapse").on("mousewheel DOMMouseScroll",function(e){var o=e.originalEvent,a=o.wheelDelta||-o.detail;this.scrollTop+=30*(a<0?1:-1),e.preventDefault()}),e(document).scroll(function(){e(this).scrollTop()>100?e(".scroll-to-top").fadeIn():e(".scroll-to-top").fadeOut()}),e('[data-toggle="tooltip"]').tooltip(),e(document).on("click","a.scroll-to-top",function(o){var a=e(this);e("html, body").stop().animate({scrollTop:e(a.attr("href")).offset().top},1e3,"easeInOutExpo"),o.preventDefault()})}(jQuery); -------------------------------------------------------------------------------- /src/main/resources/webroot/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Audit4j Microservice 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 43 |
44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/main/resources/webroot/pug/blank.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html(lang='en') 3 | 4 | head 5 | meta(charset='utf-8') 6 | meta(http-equiv='X-UA-Compatible', content='IE=edge') 7 | meta(name='viewport', content='width=device-width, initial-scale=1, shrink-to-fit=no') 8 | meta(name='description', content='') 9 | meta(name='author', content='') 10 | 11 | title SB Admin - Start Bootstrap Template 12 | 13 | include includes/css/core.pug 14 | 15 | include includes/css/custom.pug 16 | 17 | body#page-top.fixed-nav.sticky-footer.bg-dark 18 | include includes/navbar.pug 19 | .content-wrapper 20 | .container-fluid 21 | // Breadcrumbs 22 | ol.breadcrumb 23 | li.breadcrumb-item 24 | a(href='index.html') Dashboard 25 | li.breadcrumb-item.active Blank Page 26 | .row 27 | .col-12 28 | h1 Blank 29 | p This is an example of a blank page that you can use as a starting point for creating new ones. 30 | // /.container-fluid 31 | // /.content-wrapper 32 | 33 | include includes/footer.pug 34 | 35 | include includes/scroll-to-top.pug 36 | 37 | include includes/modals/logout.pug 38 | 39 | include includes/js/core.pug 40 | 41 | include includes/js/custom.pug 42 | -------------------------------------------------------------------------------- /src/main/resources/webroot/pug/cards.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html(lang='en') 3 | 4 | head 5 | meta(charset='utf-8') 6 | meta(http-equiv='X-UA-Compatible', content='IE=edge') 7 | meta(name='viewport', content='width=device-width, initial-scale=1, shrink-to-fit=no') 8 | meta(name='description', content='') 9 | meta(name='author', content='') 10 | 11 | title SB Admin - Start Bootstrap Template 12 | 13 | include includes/css/core.pug 14 | 15 | include includes/css/custom.pug 16 | 17 | body#page-top.fixed-nav.sticky-footer.bg-dark 18 | include includes/navbar.pug 19 | .content-wrapper 20 | .container-fluid 21 | // Breadcrumbs 22 | ol.breadcrumb 23 | li.breadcrumb-item 24 | a(href='#') Dashboard 25 | li.breadcrumb-item.active Cards 26 | h1 Cards 27 | hr 28 | // Icon Cards 29 | .row 30 | .col-xl-3.col-sm-6.mb-3 31 | .card.text-white.bg-primary.o-hidden.h-100 32 | .card-body 33 | .card-body-icon 34 | i.fa.fa-fw.fa-comments 35 | .mr-5 36 | | 26 New Messages! 37 | a.card-footer.text-white.clearfix.small.z-1(href='#') 38 | span.float-left View Details 39 | span.float-right 40 | i.fa.fa-angle-right 41 | .col-xl-3.col-sm-6.mb-3 42 | .card.text-white.bg-warning.o-hidden.h-100 43 | .card-body 44 | .card-body-icon 45 | i.fa.fa-fw.fa-list 46 | .mr-5 47 | | 11 New Tasks! 48 | a.card-footer.text-white.clearfix.small.z-1(href='#') 49 | span.float-left View Details 50 | span.float-right 51 | i.fa.fa-angle-right 52 | .col-xl-3.col-sm-6.mb-3 53 | .card.text-white.bg-success.o-hidden.h-100 54 | .card-body 55 | .card-body-icon 56 | i.fa.fa-fw.fa-shopping-cart 57 | .mr-5 58 | | 123 New Orders! 59 | a.card-footer.text-white.clearfix.small.z-1(href='#') 60 | span.float-left View Details 61 | span.float-right 62 | i.fa.fa-angle-right 63 | .col-xl-3.col-sm-6.mb-3 64 | .card.text-white.bg-danger.o-hidden.h-100 65 | .card-body 66 | .card-body-icon 67 | i.fa.fa-fw.fa-support 68 | .mr-5 69 | | 13 New Tickets! 70 | a.card-footer.text-white.clearfix.small.z-1(href='#') 71 | span.float-left View Details 72 | span.float-right 73 | i.fa.fa-angle-right 74 | 75 | // /.container-fluid 76 | // /.content-wrapper 77 | 78 | include includes/footer.pug 79 | 80 | include includes/scroll-to-top.pug 81 | 82 | include includes/modals/logout.pug 83 | 84 | include includes/js/core.pug 85 | 86 | include includes/js/custom.pug 87 | -------------------------------------------------------------------------------- /src/main/resources/webroot/pug/charts.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html(lang='en') 3 | 4 | head 5 | meta(charset='utf-8') 6 | meta(http-equiv='X-UA-Compatible', content='IE=edge') 7 | meta(name='viewport', content='width=device-width, initial-scale=1, shrink-to-fit=no') 8 | meta(name='description', content='') 9 | meta(name='author', content='') 10 | 11 | title SB Admin - Start Bootstrap Template 12 | 13 | include includes/css/core.pug 14 | 15 | include includes/css/custom.pug 16 | 17 | body#page-top.fixed-nav.sticky-footer.bg-dark 18 | include includes/navbar.pug 19 | .content-wrapper 20 | .container-fluid 21 | // Breadcrumbs 22 | ol.breadcrumb 23 | li.breadcrumb-item 24 | a(href='#') Dashboard 25 | li.breadcrumb-item.active Charts 26 | // Area Chart Example 27 | .card.mb-3 28 | .card-header 29 | i.fa.fa-area-chart 30 | | Area Chart Example 31 | .card-body 32 | canvas#myAreaChart(width='100%', height='30') 33 | .card-footer.small.text-muted 34 | | Updated yesterday at 11:59 PM 35 | .row 36 | .col-lg-8 37 | // Example Bar Chart Card 38 | .card.mb-3 39 | .card-header 40 | i.fa.fa-bar-chart 41 | | Bar Chart Example 42 | .card-body 43 | canvas#myBarChart(width='100', height='50') 44 | .card-footer.small.text-muted 45 | | Updated yesterday at 11:59 PM 46 | .col-lg-4 47 | // Example Pie Chart Card 48 | .card.mb-3 49 | .card-header 50 | i.fa.fa-pie-chart 51 | | Pie Chart Example 52 | .card-body 53 | canvas#myPieChart(width='100%', height='100') 54 | .card-footer.small.text-muted 55 | | Updated yesterday at 11:59 PM 56 | // /.container-fluid 57 | // /.content-wrapper 58 | 59 | include includes/footer.pug 60 | 61 | include includes/scroll-to-top.pug 62 | 63 | include includes/modals/logout.pug 64 | 65 | include includes/js/core.pug 66 | 67 | // Page level plugin JavaScript 68 | script(src='vendor/chart.js/Chart.min.js') 69 | 70 | include includes/js/custom.pug 71 | 72 | // Custom scripts for this page 73 | script(src='js/sb-admin-charts.min.js') 74 | -------------------------------------------------------------------------------- /src/main/resources/webroot/pug/forgot-password.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html(lang='en') 3 | 4 | head 5 | meta(charset='utf-8') 6 | meta(http-equiv='X-UA-Compatible', content='IE=edge') 7 | meta(name='viewport', content='width=device-width, initial-scale=1, shrink-to-fit=no') 8 | meta(name='description', content='') 9 | meta(name='author', content='') 10 | 11 | title SB Admin - Start Bootstrap Template 12 | 13 | include includes/css/core.pug 14 | 15 | include includes/css/custom.pug 16 | 17 | body.bg-dark 18 | .container 19 | .card.card-login.mx-auto.mt-5 20 | .card-header 21 | | Reset Password 22 | .card-body 23 | .text-center.mt-4.mb-5 24 | h4 Forgot your password? 25 | p 26 | | Enter your email address and we will send you instructions on how to reset your password. 27 | form 28 | .form-group 29 | input#exampleInputEmail1.form-control(type='email', aria-describedby='emailHelp', placeholder='Enter email address') 30 | a.btn.btn-primary.btn-block(href='login.html') Reset Password 31 | .text-center 32 | a.d-block.small.mt-3(href='register.html') Register an Account 33 | a.d-block.small(href='login.html') Login Page 34 | 35 | include includes/js/core.pug 36 | -------------------------------------------------------------------------------- /src/main/resources/webroot/pug/includes/css/core.pug: -------------------------------------------------------------------------------- 1 | // Bootstrap core CSS 2 | link(href='vendor/bootstrap/css/bootstrap.min.css', rel='stylesheet') 3 | // Custom fonts for this template 4 | link(href='vendor/font-awesome/css/font-awesome.min.css', rel='stylesheet', type='text/css') 5 | -------------------------------------------------------------------------------- /src/main/resources/webroot/pug/includes/css/custom.pug: -------------------------------------------------------------------------------- 1 | // Custom styles for this template 2 | link(href='css/sb-admin.css', rel='stylesheet') 3 | -------------------------------------------------------------------------------- /src/main/resources/webroot/pug/includes/footer.pug: -------------------------------------------------------------------------------- 1 | footer.sticky-footer 2 | .container 3 | .text-center 4 | small Copyright © Your Website 2017 5 | -------------------------------------------------------------------------------- /src/main/resources/webroot/pug/includes/js/core.pug: -------------------------------------------------------------------------------- 1 | // Bootstrap core JavaScript 2 | script(src='vendor/jquery/jquery.min.js') 3 | script(src='vendor/bootstrap/js/bootstrap.bundle.min.js') 4 | // Core plugin JavaScript 5 | script(src='vendor/jquery-easing/jquery.easing.min.js') 6 | -------------------------------------------------------------------------------- /src/main/resources/webroot/pug/includes/js/custom.pug: -------------------------------------------------------------------------------- 1 | // Custom scripts for all pages 2 | script(src='js/sb-admin.min.js') 3 | -------------------------------------------------------------------------------- /src/main/resources/webroot/pug/includes/modals/logout.pug: -------------------------------------------------------------------------------- 1 | // Logout Modal 2 | #exampleModal.modal.fade(tabindex='-1', role='dialog', aria-labelledby='exampleModalLabel', aria-hidden='true') 3 | .modal-dialog(role='document') 4 | .modal-content 5 | .modal-header 6 | h5#exampleModalLabel.modal-title Ready to Leave? 7 | button.close(type='button', data-dismiss='modal', aria-label='Close') 8 | span(aria-hidden='true') × 9 | .modal-body 10 | | Select "Logout" below if you are ready to end your current session. 11 | .modal-footer 12 | button.btn.btn-secondary(type='button', data-dismiss='modal') Cancel 13 | a.btn.btn-primary(href='login.html') Logout 14 | -------------------------------------------------------------------------------- /src/main/resources/webroot/pug/includes/navbar.pug: -------------------------------------------------------------------------------- 1 | // Navigation 2 | nav#mainNav.navbar.navbar-expand-lg.navbar-dark.bg-dark.fixed-top 3 | a.navbar-brand(href='index.html') Start Bootstrap 4 | button.navbar-toggler.navbar-toggler-right(type='button', data-toggle='collapse', data-target='#navbarResponsive', aria-controls='navbarResponsive', aria-expanded='false', aria-label='Toggle navigation') 5 | span.navbar-toggler-icon 6 | #navbarResponsive.collapse.navbar-collapse 7 | ul#exampleAccordion.navbar-nav.navbar-sidenav 8 | li.nav-item(data-toggle='tooltip', data-placement='right', title='Dashboard') 9 | a.nav-link(href='index.html') 10 | i.fa.fa-fw.fa-dashboard 11 | span.nav-link-text 12 | | Dashboard 13 | li.nav-item(data-toggle='tooltip', data-placement='right', title='Charts') 14 | a.nav-link(href='charts.html') 15 | i.fa.fa-fw.fa-area-chart 16 | span.nav-link-text 17 | | Charts 18 | li.nav-item(data-toggle='tooltip', data-placement='right', title='Tables') 19 | a.nav-link(href='tables.html') 20 | i.fa.fa-fw.fa-table 21 | span.nav-link-text 22 | | Tables 23 | li.nav-item(data-toggle='tooltip', data-placement='right', title='Components') 24 | a.nav-link.nav-link-collapse.collapsed(data-toggle='collapse', href='#collapseComponents', data-parent='#exampleAccordion') 25 | i.fa.fa-fw.fa-wrench 26 | span.nav-link-text 27 | | Components 28 | ul#collapseComponents.sidenav-second-level.collapse 29 | li 30 | a(href='navbar.html') Navbar 31 | li 32 | a(href='cards.html') Cards 33 | li.nav-item(data-toggle='tooltip', data-placement='right', title='Example Pages') 34 | a.nav-link.nav-link-collapse.collapsed(data-toggle='collapse', href='#collapseExamplePages', data-parent='#exampleAccordion') 35 | i.fa.fa-fw.fa-file 36 | span.nav-link-text 37 | | Example Pages 38 | ul#collapseExamplePages.sidenav-second-level.collapse 39 | li 40 | a(href='login.html') Login Page 41 | li 42 | a(href='register.html') Registration Page 43 | li 44 | a(href='forgot-password.html') Forgot Password Page 45 | li 46 | a(href='blank.html') Blank Page 47 | li.nav-item(data-toggle='tooltip', data-placement='right', title='Menu Levels') 48 | a.nav-link.nav-link-collapse.collapsed(data-toggle='collapse', href='#collapseMulti', data-parent='#exampleAccordion') 49 | i.fa.fa-fw.fa-sitemap 50 | span.nav-link-text 51 | | Menu Levels 52 | ul#collapseMulti.sidenav-second-level.collapse 53 | li 54 | a(href='#') Second Level Item 55 | li 56 | a(href='#') Second Level Item 57 | li 58 | a(href='#') Second Level Item 59 | li 60 | a.nav-link-collapse.collapsed(data-toggle='collapse', href='#collapseMulti2') Third Level 61 | ul#collapseMulti2.sidenav-third-level.collapse 62 | li 63 | a(href='#') Third Level Item 64 | li 65 | a(href='#') Third Level Item 66 | li 67 | a(href='#') Third Level Item 68 | li.nav-item(data-toggle='tooltip', data-placement='right', title='Link') 69 | a.nav-link(href='#') 70 | i.fa.fa-fw.fa-link 71 | span.nav-link-text 72 | | Link 73 | ul.navbar-nav.sidenav-toggler 74 | li.nav-item 75 | a#sidenavToggler.nav-link.text-center 76 | i.fa.fa-fw.fa-angle-left 77 | ul.navbar-nav.ml-auto 78 | li.nav-item.dropdown 79 | a#messagesDropdown.nav-link.dropdown-toggle.mr-lg-2(href='#', data-toggle='dropdown', aria-haspopup='true', aria-expanded='false') 80 | i.fa.fa-fw.fa-envelope 81 | span.d-lg-none 82 | | Messages 83 | span.badge.badge-pill.badge-primary 12 New 84 | span.indicator.text-primary.d-none.d-lg-block 85 | i.fa.fa-fw.fa-circle 86 | .dropdown-menu(aria-labelledby='messagesDropdown') 87 | h6.dropdown-header New Messages: 88 | .dropdown-divider 89 | a.dropdown-item(href='#') 90 | strong David Miller 91 | span.small.float-right.text-muted 11:21 AM 92 | .dropdown-message.small 93 | | Hey there! This new version of SB Admin is pretty awesome! These messages clip off when they reach the end of the box so they don't overflow over to the sides! 94 | .dropdown-divider 95 | a.dropdown-item(href='#') 96 | strong Jane Smith 97 | span.small.float-right.text-muted 11:21 AM 98 | .dropdown-message.small 99 | | I was wondering if you could meet for an appointment at 3:00 instead of 4:00. Thanks! 100 | .dropdown-divider 101 | a.dropdown-item(href='#') 102 | strong John Doe 103 | span.small.float-right.text-muted 11:21 AM 104 | .dropdown-message.small 105 | | I've sent the final files over to you for review. When you're able to sign off of them let me know and we can discuss distribution. 106 | .dropdown-divider 107 | a.dropdown-item.small(href='#') 108 | | View all messages 109 | li.nav-item.dropdown 110 | a#alertsDropdown.nav-link.dropdown-toggle.mr-lg-2(href='#', data-toggle='dropdown', aria-haspopup='true', aria-expanded='false') 111 | i.fa.fa-fw.fa-bell 112 | span.d-lg-none 113 | | Alerts 114 | span.badge.badge-pill.badge-warning 6 New 115 | span.indicator.text-warning.d-none.d-lg-block 116 | i.fa.fa-fw.fa-circle 117 | .dropdown-menu(aria-labelledby='alertsDropdown') 118 | h6.dropdown-header New Alerts: 119 | .dropdown-divider 120 | a.dropdown-item(href='#') 121 | span.text-success 122 | strong 123 | i.fa.fa-long-arrow-up.fa-fw 124 | | Status Update 125 | span.small.float-right.text-muted 11:21 AM 126 | .dropdown-message.small This is an automated server response message. All systems are online. 127 | .dropdown-divider 128 | a.dropdown-item(href='#') 129 | span.text-danger 130 | strong 131 | i.fa.fa-long-arrow-down.fa-fw 132 | | Status Update 133 | span.small.float-right.text-muted 11:21 AM 134 | .dropdown-message.small This is an automated server response message. All systems are online. 135 | .dropdown-divider 136 | a.dropdown-item(href='#') 137 | span.text-success 138 | strong 139 | i.fa.fa-long-arrow-up.fa-fw 140 | | Status Update 141 | span.small.float-right.text-muted 11:21 AM 142 | .dropdown-message.small This is an automated server response message. All systems are online. 143 | .dropdown-divider 144 | a.dropdown-item.small(href='#') 145 | | View all alerts 146 | li.nav-item 147 | form.form-inline.my-2.my-lg-0.mr-lg-2 148 | .input-group 149 | input.form-control(type='text', placeholder='Search for...') 150 | span.input-group-btn 151 | button.btn.btn-primary(type='button') 152 | i.fa.fa-search 153 | li.nav-item 154 | a.nav-link(data-toggle='modal', data-target='#exampleModal') 155 | i.fa.fa-fw.fa-sign-out 156 | | Logout 157 | -------------------------------------------------------------------------------- /src/main/resources/webroot/pug/includes/scroll-to-top.pug: -------------------------------------------------------------------------------- 1 | // Scroll to Top Button 2 | a.scroll-to-top.rounded(href='#page-top') 3 | i.fa.fa-angle-up 4 | -------------------------------------------------------------------------------- /src/main/resources/webroot/pug/login.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html(lang='en') 3 | 4 | head 5 | meta(charset='utf-8') 6 | meta(http-equiv='X-UA-Compatible', content='IE=edge') 7 | meta(name='viewport', content='width=device-width, initial-scale=1, shrink-to-fit=no') 8 | meta(name='description', content='') 9 | meta(name='author', content='') 10 | 11 | title SB Admin - Start Bootstrap Template 12 | 13 | include includes/css/core.pug 14 | 15 | include includes/css/custom.pug 16 | 17 | body.bg-dark 18 | .container 19 | .card.card-login.mx-auto.mt-5 20 | .card-header 21 | | Login 22 | .card-body 23 | form 24 | .form-group 25 | label(for='exampleInputEmail1') Email address 26 | input#exampleInputEmail1.form-control(type='email', aria-describedby='emailHelp', placeholder='Enter email') 27 | .form-group 28 | label(for='exampleInputPassword1') Password 29 | input#exampleInputPassword1.form-control(type='password', placeholder='Password') 30 | .form-group 31 | .form-check 32 | label.form-check-label 33 | input.form-check-input(type='checkbox') 34 | | Remember Password 35 | a.btn.btn-primary.btn-block(href='index.html') Login 36 | .text-center 37 | a.d-block.small.mt-3(href='register.html') Register an Account 38 | a.d-block.small(href='forgot-password.html') Forgot Password? 39 | 40 | include includes/js/core.pug 41 | -------------------------------------------------------------------------------- /src/main/resources/webroot/pug/navbar.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html(lang='en') 3 | 4 | head 5 | meta(charset='utf-8') 6 | meta(http-equiv='X-UA-Compatible', content='IE=edge') 7 | meta(name='viewport', content='width=device-width, initial-scale=1, shrink-to-fit=no') 8 | meta(name='description', content='') 9 | meta(name='author', content='') 10 | 11 | title SB Admin - Start Bootstrap Template 12 | 13 | include includes/css/core.pug 14 | 15 | include includes/css/custom.pug 16 | 17 | body#page-top.fixed-nav.sticky-footer.bg-dark 18 | include includes/navbar.pug 19 | .content-wrapper 20 | .container-fluid 21 | // Breadcrumbs 22 | ol.breadcrumb 23 | li.breadcrumb-item 24 | a(href='#') Dashboard 25 | li.breadcrumb-item.active Navbar 26 | h1 Navbar 27 | hr 28 | p The SB Admin navbar can be either fixed or static, and it supports the navbar-light and navbar-dark Bootstrap 4 classes. 29 | a(href='#').btn.btn-primary#toggleNavPosition Toggle Fixed/Static Navbar 30 | a(href='#').btn.btn-primary#toggleNavColor Toggle Navbar Color 31 | 32 | // Blank div to give the page height to preview the fixed vs. static navbar 33 | div(style='height: 1000px') 34 | // /.container-fluid 35 | // /.content-wrapper 36 | 37 | include includes/footer.pug 38 | 39 | include includes/scroll-to-top.pug 40 | 41 | include includes/modals/logout.pug 42 | 43 | include includes/js/core.pug 44 | 45 | include includes/js/custom.pug 46 | 47 | // Custom scripts for this page 48 | 49 | // Toggle between fixed and static navbar 50 | script. 51 | $('#toggleNavPosition').click(function() { 52 | $('body').toggleClass('fixed-nav'); 53 | $('nav').toggleClass('fixed-top static-top'); 54 | }); 55 | 56 | // Toggle between dark and light navbar 57 | script. 58 | $('#toggleNavColor').click(function() { 59 | $('nav').toggleClass('navbar-dark navbar-light'); 60 | $('nav').toggleClass('bg-dark bg-light'); 61 | $('body').toggleClass('bg-dark bg-light'); 62 | }); 63 | -------------------------------------------------------------------------------- /src/main/resources/webroot/pug/register.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html(lang='en') 3 | 4 | head 5 | meta(charset='utf-8') 6 | meta(http-equiv='X-UA-Compatible', content='IE=edge') 7 | meta(name='viewport', content='width=device-width, initial-scale=1, shrink-to-fit=no') 8 | meta(name='description', content='') 9 | meta(name='author', content='') 10 | 11 | title SB Admin - Start Bootstrap Template 12 | 13 | include includes/css/core.pug 14 | 15 | include includes/css/custom.pug 16 | 17 | body.bg-dark 18 | .container 19 | .card.card-register.mx-auto.mt-5 20 | .card-header 21 | | Register an Account 22 | .card-body 23 | form 24 | .form-group 25 | .form-row 26 | .col-md-6 27 | label(for='exampleInputName') First name 28 | input#exampleInputName.form-control(type='text', aria-describedby='nameHelp', placeholder='Enter first name') 29 | .col-md-6 30 | label(for='exampleInputLastName') Last name 31 | input#exampleInputLastName.form-control(type='text', aria-describedby='nameHelp', placeholder='Enter last name') 32 | .form-group 33 | label(for='exampleInputEmail1') Email address 34 | input#exampleInputEmail1.form-control(type='email', aria-describedby='emailHelp', placeholder='Enter email') 35 | .form-group 36 | .form-row 37 | .col-md-6 38 | label(for='exampleInputPassword1') Password 39 | input#exampleInputPassword1.form-control(type='password', placeholder='Password') 40 | .col-md-6 41 | label(for='exampleConfirmPassword') Confirm password 42 | input#exampleConfirmPassword.form-control(type='password', placeholder='Confirm password') 43 | a.btn.btn-primary.btn-block(href='login.html') Register 44 | .text-center 45 | a.d-block.small.mt-3(href='login.html') Login Page 46 | a.d-block.small(href='forgot-password.html') Forgot Password? 47 | 48 | include includes/js/core.pug 49 | -------------------------------------------------------------------------------- /src/main/resources/webroot/scss/_cards.scss: -------------------------------------------------------------------------------- 1 | // Styling for custom cards 2 | // Custom class for the background icon in card blocks 3 | .card-body-icon { 4 | position: absolute; 5 | z-index: 0; 6 | top: -25px; 7 | right: -25px; 8 | 9 | font-size: 5rem; 10 | @include rotate; 11 | } 12 | 13 | // Override breakpoints for card columns to work well with sidebar 14 | .card-columns { 15 | @media (min-width: 576px) { 16 | column-count: 1; 17 | } 18 | @media (min-width: 768px) { 19 | column-count: 2; 20 | } 21 | @media (min-width: 1200px) { 22 | column-count: 2; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/resources/webroot/scss/_footer.scss: -------------------------------------------------------------------------------- 1 | footer.sticky-footer { 2 | position: absolute; 3 | right: 0; 4 | bottom: 0; 5 | 6 | width: 100%; 7 | height: 56px; 8 | 9 | background-color: $gray-200; 10 | 11 | line-height: 55px; 12 | @media (min-width: 992px) { 13 | width: calc(100% - #{$sidenav-base-width}); 14 | } 15 | } 16 | 17 | body.sidenav-toggled { 18 | @media (min-width: 992px) { 19 | footer.sticky-footer { 20 | width: calc(100% - #{$sidenav-collapsed-width}); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/resources/webroot/scss/_global.scss: -------------------------------------------------------------------------------- 1 | // Global styling for this template 2 | 3 | html { 4 | position: relative; 5 | min-height: 100%; 6 | } 7 | 8 | body { 9 | overflow-x: hidden; 10 | } 11 | 12 | body.sticky-footer { 13 | margin-bottom: 56px; 14 | .content-wrapper { 15 | min-height: calc(100vh - 56px - 56px); 16 | } 17 | } 18 | 19 | body.fixed-nav { 20 | padding-top: 56px; 21 | } 22 | 23 | .content-wrapper { 24 | min-height: calc(100vh - 56px); 25 | padding-top: 1rem; 26 | } 27 | 28 | // Scroll to top button 29 | .scroll-to-top { 30 | position: fixed; 31 | right: 15px; 32 | bottom: 3px; 33 | 34 | display: none; 35 | 36 | width: 50px; 37 | height: 50px; 38 | 39 | text-align: center; 40 | 41 | color: white; 42 | background: fade-out($gray-800, .5); 43 | 44 | line-height: 45px; 45 | &:focus, 46 | &:hover { 47 | color: white; 48 | } 49 | &:hover { 50 | background: $gray-800; 51 | } 52 | i { 53 | font-weight: 800; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/resources/webroot/scss/_login.scss: -------------------------------------------------------------------------------- 1 | .card-login { 2 | max-width: 25rem; 3 | } 4 | 5 | .card-register { 6 | max-width: 40rem; 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/webroot/scss/_mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin rotate { 2 | -webkit-transform: rotate(15deg); 3 | -ms-transform: rotate(15deg); 4 | transform: rotate(15deg); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/resources/webroot/scss/_utilities.scss: -------------------------------------------------------------------------------- 1 | // Additional Text Helper Class 2 | .smaller { 3 | font-size: 0.7rem; 4 | } 5 | 6 | // Helper class for the overflow property 7 | .o-hidden { 8 | overflow: hidden !important; 9 | } 10 | 11 | // Helper classes for z-index 12 | .z-0 { 13 | z-index: 0; 14 | } 15 | 16 | .z-1 { 17 | z-index: 1; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/resources/webroot/scss/_variables.scss: -------------------------------------------------------------------------------- 1 | // Color Variables 2 | // Bootstrap Color Defaults 3 | $white: #fff !default; 4 | $gray-100: #f8f9fa !default; 5 | $gray-200: #e9ecef !default; 6 | $gray-300: #dee2e6 !default; 7 | $gray-400: #ced4da !default; 8 | $gray-500: #adb5bd !default; 9 | $gray-600: #868e96 !default; 10 | $gray-700: #495057 !default; 11 | $gray-800: #343a40 !default; 12 | $gray-900: #212529 !default; 13 | $black: #000 !default; 14 | 15 | $blue: #007bff !default; 16 | $indigo: #6610f2 !default; 17 | $purple: #6f42c1 !default; 18 | $pink: #e83e8c !default; 19 | $red: #dc3545 !default; 20 | $orange: #fd7e14 !default; 21 | $yellow: #ffc107 !default; 22 | $green: #28a745 !default; 23 | $teal: #20c997 !default; 24 | $cyan: #17a2b8 !default; 25 | 26 | // Spacing Variables 27 | // Change below variable if the height of the navbar changes 28 | $navbar-base-height: 56px; 29 | // Change below variable to change the width of the sidenav 30 | $sidenav-base-width: 250px; 31 | // Change below variable to change the width of the sidenav when collapsed 32 | $sidenav-collapsed-width: 55px; 33 | -------------------------------------------------------------------------------- /src/main/resources/webroot/scss/navbar/_navbar_colors.scss: -------------------------------------------------------------------------------- 1 | // Color support for .navbar-dark 2 | 3 | #mainNav.navbar-dark { 4 | .navbar-collapse { 5 | .navbar-sidenav { 6 | .nav-link-collapse:after { 7 | color: $gray-600; 8 | } 9 | > .nav-item { 10 | > .nav-link { 11 | color: $gray-600; 12 | &:hover { 13 | color: $gray-500; 14 | } 15 | } 16 | .sidenav-second-level, 17 | .sidenav-third-level { 18 | > li > a { 19 | color: $gray-600; 20 | &:focus, 21 | &:hover { 22 | color: $gray-500; 23 | } 24 | } 25 | } 26 | } 27 | } 28 | .navbar-nav > .nav-item.dropdown > .nav-link:after { 29 | color: $gray-500; 30 | } 31 | } 32 | @media (min-width: 992px) { 33 | .navbar-collapse { 34 | .navbar-sidenav { 35 | background: $gray-800; 36 | li { 37 | &.active { 38 | a { 39 | color: white !important; 40 | background-color: $gray-700; 41 | &:focus, 42 | &:hover { 43 | color: white; 44 | } 45 | } 46 | } 47 | } 48 | > .nav-item { 49 | .sidenav-second-level, 50 | .sidenav-third-level { 51 | background: $gray-800; 52 | } 53 | } 54 | } 55 | } 56 | } 57 | } 58 | 59 | // Color support for .navbar-light 60 | 61 | #mainNav.navbar-light { 62 | .navbar-collapse { 63 | .navbar-sidenav { 64 | .nav-link-collapse:after { 65 | color: fade-out($black, 0.5); 66 | } 67 | > .nav-item { 68 | > .nav-link { 69 | color: fade-out($black, 0.5); 70 | &:hover { 71 | color: fade-out($black, 0.3); 72 | } 73 | } 74 | .sidenav-second-level, 75 | .sidenav-third-level { 76 | > li > a { 77 | color: fade-out($black, 0.5); 78 | &:focus, 79 | &:hover { 80 | color: fade-out($black, 0.3); 81 | } 82 | } 83 | } 84 | } 85 | } 86 | .navbar-nav > .nav-item.dropdown > .nav-link:after { 87 | color: fade-out($black, 0.5); 88 | } 89 | } 90 | @media (min-width: 992px) { 91 | .navbar-collapse { 92 | .navbar-sidenav { 93 | background: $gray-100; 94 | li { 95 | &.active { 96 | a { 97 | color: $black !important; 98 | background-color: $gray-200; 99 | &:focus, 100 | &:hover { 101 | color: $black; 102 | } 103 | } 104 | } 105 | } 106 | > .nav-item { 107 | .sidenav-second-level, 108 | .sidenav-third-level { 109 | background: $gray-100; 110 | } 111 | } 112 | } 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/main/resources/webroot/scss/navbar/_navbar_fixed.scss: -------------------------------------------------------------------------------- 1 | #mainNav.fixed-top { 2 | .sidenav-toggler { 3 | display: none; 4 | } 5 | @media (min-width: 992px) { 6 | .navbar-sidenav { 7 | height: calc(100vh - 112px); 8 | } 9 | .sidenav-toggler { 10 | position: absolute; 11 | top: 0; 12 | left: 0; 13 | 14 | display: flex; 15 | overflow-x: hidden; 16 | overflow-y: auto; 17 | -webkit-flex-direction: column; 18 | -ms-flex-direction: column; 19 | flex-direction: column; 20 | 21 | margin-top: calc(100vh - 56px); 22 | 23 | > .nav-item { 24 | width: $sidenav-base-width; 25 | padding: 0; 26 | > .nav-link { 27 | padding: 1em; 28 | } 29 | } 30 | } 31 | } 32 | &.navbar-dark { 33 | .sidenav-toggler { 34 | background-color: $gray-900; 35 | a { 36 | i { 37 | color: $gray-500;; 38 | } 39 | } 40 | } 41 | } 42 | &.navbar-light { 43 | .sidenav-toggler { 44 | background-color: $gray-300; 45 | a { 46 | i { 47 | color: fade-out($black, 0.5); 48 | } 49 | } 50 | } 51 | } 52 | } 53 | 54 | body.sidenav-toggled { 55 | #mainNav.fixed-top { 56 | .sidenav-toggler { 57 | overflow-x: hidden; 58 | 59 | width: $sidenav-collapsed-width; 60 | .nav-item, 61 | .nav-link { 62 | width: $sidenav-collapsed-width !important; 63 | } 64 | } 65 | #sidenavToggler { 66 | i { 67 | -webkit-transform: scaleX(-1); 68 | -moz-transform: scaleX(-1); 69 | -o-transform: scaleX(-1); 70 | transform: scaleX(-1); 71 | filter: FlipH; 72 | -ms-filter: 'FlipH'; 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/resources/webroot/scss/navbar/_navbar_global.scss: -------------------------------------------------------------------------------- 1 | #mainNav { 2 | .navbar-collapse { 3 | overflow: auto; 4 | 5 | max-height: 75vh; 6 | .navbar-nav { 7 | .nav-item { 8 | .nav-link { 9 | cursor: pointer; 10 | } 11 | } 12 | } 13 | .navbar-sidenav { 14 | .nav-link-collapse:after { 15 | float: right; 16 | 17 | content: '\f107'; 18 | 19 | font-family: 'FontAwesome'; 20 | } 21 | .nav-link-collapse.collapsed:after { 22 | content: '\f105'; 23 | } 24 | .sidenav-second-level, 25 | .sidenav-third-level { 26 | padding-left: 0; 27 | > li > a { 28 | display: block; 29 | 30 | padding: 0.5em 0; 31 | &:focus, 32 | &:hover { 33 | text-decoration: none; 34 | } 35 | } 36 | } 37 | .sidenav-second-level > li > a { 38 | padding-left: 1em; 39 | } 40 | .sidenav-third-level > li > a { 41 | padding-left: 2em; 42 | } 43 | } 44 | .sidenav-toggler { 45 | display: none; 46 | } 47 | .navbar-nav > .nav-item.dropdown { 48 | > .nav-link { 49 | position: relative; 50 | 51 | min-width: 45px; 52 | &:after { 53 | float: right; 54 | 55 | width: auto; 56 | 57 | content: '\f105'; 58 | 59 | border: none; 60 | 61 | font-family: 'FontAwesome'; 62 | } 63 | .indicator { 64 | position: absolute; 65 | top: 5px; 66 | left: 21px; 67 | font-size: 10px; 68 | } 69 | } 70 | &.show > .nav-link:after { 71 | content: '\f107'; 72 | } 73 | .dropdown-menu > .dropdown-item > .dropdown-message { 74 | overflow: hidden; 75 | 76 | max-width: none; 77 | 78 | text-overflow: ellipsis; 79 | } 80 | } 81 | } 82 | @media (min-width: 992px) { 83 | .navbar-brand { 84 | width: $sidenav-base-width; 85 | } 86 | .navbar-collapse { 87 | overflow: visible; 88 | 89 | max-height: none; 90 | .navbar-sidenav { 91 | position: absolute; 92 | top: 0; 93 | left: 0; 94 | 95 | overflow-x: hidden; 96 | overflow-y: auto; 97 | -webkit-flex-direction: column; 98 | -ms-flex-direction: column; 99 | flex-direction: column; 100 | 101 | margin-top: $navbar-base-height; 102 | 103 | > .nav-item { 104 | width: $sidenav-base-width; 105 | padding: 0; 106 | > .nav-link { 107 | padding: 1em; 108 | } 109 | .sidenav-second-level, 110 | .sidenav-third-level { 111 | padding-left: 0; 112 | 113 | list-style: none; 114 | 115 | > li { 116 | width: $sidenav-base-width; 117 | > a { 118 | padding: 1em; 119 | } 120 | } 121 | } 122 | .sidenav-second-level > li > a { 123 | padding-left: 2.75em; 124 | } 125 | .sidenav-third-level > li > a { 126 | padding-left: 3.75em; 127 | } 128 | } 129 | } 130 | .navbar-nav > .nav-item.dropdown { 131 | > .nav-link { 132 | min-width: 0; 133 | &:after { 134 | width: 24px; 135 | 136 | text-align: center; 137 | } 138 | } 139 | .dropdown-menu > .dropdown-item > .dropdown-message { 140 | max-width: 300px; 141 | } 142 | } 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/main/resources/webroot/scss/navbar/_navbar_static.scss: -------------------------------------------------------------------------------- 1 | #mainNav.static-top { 2 | .sidenav-toggler { 3 | display: none; 4 | } 5 | @media (min-width: 992px) { 6 | .sidenav-toggler { 7 | display: flex; 8 | } 9 | } 10 | } 11 | 12 | body.sidenav-toggled { 13 | #mainNav.static-top { 14 | #sidenavToggler { 15 | i { 16 | -webkit-transform: scaleX(-1); 17 | -moz-transform: scaleX(-1); 18 | -o-transform: scaleX(-1); 19 | transform: scaleX(-1); 20 | filter: FlipH; 21 | -ms-filter: 'FlipH'; 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/resources/webroot/scss/navbar/_navbar_toggle.scss: -------------------------------------------------------------------------------- 1 | .content-wrapper { 2 | overflow-x: hidden; 3 | 4 | background: white; 5 | @media (min-width: 992px) { 6 | margin-left: $sidenav-base-width; 7 | } 8 | } 9 | 10 | // Toggling the Sidenav 11 | #sidenavToggler { 12 | i { 13 | font-weight: 800; 14 | } 15 | } 16 | 17 | .navbar-sidenav-tooltip.show { 18 | display: none; 19 | } 20 | 21 | body.sidenav-toggled { 22 | .content-wrapper { 23 | @media (min-width: 992px) { 24 | margin-left: $sidenav-collapsed-width; 25 | } 26 | } 27 | .navbar-sidenav { 28 | overflow-x: hidden; 29 | 30 | width: $sidenav-collapsed-width; 31 | .nav-link-text { 32 | display: none; 33 | } 34 | .nav-item, 35 | .nav-link { 36 | width: $sidenav-collapsed-width !important; 37 | &:after { 38 | display: none; 39 | } 40 | } 41 | } 42 | .navbar-sidenav-tooltip.show { 43 | display: flex; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/resources/webroot/scss/sb-admin.scss: -------------------------------------------------------------------------------- 1 | @import "variables.scss"; 2 | @import "mixins.scss"; 3 | @import "global.scss"; 4 | @import "utilities.scss"; 5 | @import "navbar/navbar_global.scss"; 6 | @import "navbar/navbar_fixed.scss"; 7 | @import "navbar/navbar_static.scss"; 8 | @import "navbar/navbar_toggle.scss"; 9 | @import "navbar/navbar_colors.scss"; 10 | @import "cards.scss"; 11 | @import "login.scss"; 12 | @import "footer.scss"; 13 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/bootstrap/css/bootstrap-reboot.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v4.0.0-beta.2 (https://getbootstrap.com) 3 | * Copyright 2011-2017 The Bootstrap Authors 4 | * Copyright 2011-2017 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */ 8 | *, 9 | *::before, 10 | *::after { 11 | box-sizing: border-box; 12 | } 13 | 14 | html { 15 | font-family: sans-serif; 16 | line-height: 1.15; 17 | -webkit-text-size-adjust: 100%; 18 | -ms-text-size-adjust: 100%; 19 | -ms-overflow-style: scrollbar; 20 | -webkit-tap-highlight-color: transparent; 21 | } 22 | 23 | @-ms-viewport { 24 | width: device-width; 25 | } 26 | 27 | article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section { 28 | display: block; 29 | } 30 | 31 | body { 32 | margin: 0; 33 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; 34 | font-size: 1rem; 35 | font-weight: 400; 36 | line-height: 1.5; 37 | color: #212529; 38 | text-align: left; 39 | background-color: #fff; 40 | } 41 | 42 | [tabindex="-1"]:focus { 43 | outline: none !important; 44 | } 45 | 46 | hr { 47 | box-sizing: content-box; 48 | height: 0; 49 | overflow: visible; 50 | } 51 | 52 | h1, h2, h3, h4, h5, h6 { 53 | margin-top: 0; 54 | margin-bottom: 0.5rem; 55 | } 56 | 57 | p { 58 | margin-top: 0; 59 | margin-bottom: 1rem; 60 | } 61 | 62 | abbr[title], 63 | abbr[data-original-title] { 64 | text-decoration: underline; 65 | -webkit-text-decoration: underline dotted; 66 | text-decoration: underline dotted; 67 | cursor: help; 68 | border-bottom: 0; 69 | } 70 | 71 | address { 72 | margin-bottom: 1rem; 73 | font-style: normal; 74 | line-height: inherit; 75 | } 76 | 77 | ol, 78 | ul, 79 | dl { 80 | margin-top: 0; 81 | margin-bottom: 1rem; 82 | } 83 | 84 | ol ol, 85 | ul ul, 86 | ol ul, 87 | ul ol { 88 | margin-bottom: 0; 89 | } 90 | 91 | dt { 92 | font-weight: 700; 93 | } 94 | 95 | dd { 96 | margin-bottom: .5rem; 97 | margin-left: 0; 98 | } 99 | 100 | blockquote { 101 | margin: 0 0 1rem; 102 | } 103 | 104 | dfn { 105 | font-style: italic; 106 | } 107 | 108 | b, 109 | strong { 110 | font-weight: bolder; 111 | } 112 | 113 | small { 114 | font-size: 80%; 115 | } 116 | 117 | sub, 118 | sup { 119 | position: relative; 120 | font-size: 75%; 121 | line-height: 0; 122 | vertical-align: baseline; 123 | } 124 | 125 | sub { 126 | bottom: -.25em; 127 | } 128 | 129 | sup { 130 | top: -.5em; 131 | } 132 | 133 | a { 134 | color: #007bff; 135 | text-decoration: none; 136 | background-color: transparent; 137 | -webkit-text-decoration-skip: objects; 138 | } 139 | 140 | a:hover { 141 | color: #0056b3; 142 | text-decoration: underline; 143 | } 144 | 145 | a:not([href]):not([tabindex]) { 146 | color: inherit; 147 | text-decoration: none; 148 | } 149 | 150 | a:not([href]):not([tabindex]):focus, a:not([href]):not([tabindex]):hover { 151 | color: inherit; 152 | text-decoration: none; 153 | } 154 | 155 | a:not([href]):not([tabindex]):focus { 156 | outline: 0; 157 | } 158 | 159 | pre, 160 | code, 161 | kbd, 162 | samp { 163 | font-family: monospace, monospace; 164 | font-size: 1em; 165 | } 166 | 167 | pre { 168 | margin-top: 0; 169 | margin-bottom: 1rem; 170 | overflow: auto; 171 | -ms-overflow-style: scrollbar; 172 | } 173 | 174 | figure { 175 | margin: 0 0 1rem; 176 | } 177 | 178 | img { 179 | vertical-align: middle; 180 | border-style: none; 181 | } 182 | 183 | svg:not(:root) { 184 | overflow: hidden; 185 | } 186 | 187 | a, 188 | area, 189 | button, 190 | [role="button"], 191 | input:not([type="range"]), 192 | label, 193 | select, 194 | summary, 195 | textarea { 196 | -ms-touch-action: manipulation; 197 | touch-action: manipulation; 198 | } 199 | 200 | table { 201 | border-collapse: collapse; 202 | } 203 | 204 | caption { 205 | padding-top: 0.75rem; 206 | padding-bottom: 0.75rem; 207 | color: #868e96; 208 | text-align: left; 209 | caption-side: bottom; 210 | } 211 | 212 | th { 213 | text-align: inherit; 214 | } 215 | 216 | label { 217 | display: inline-block; 218 | margin-bottom: .5rem; 219 | } 220 | 221 | button { 222 | border-radius: 0; 223 | } 224 | 225 | button:focus { 226 | outline: 1px dotted; 227 | outline: 5px auto -webkit-focus-ring-color; 228 | } 229 | 230 | input, 231 | button, 232 | select, 233 | optgroup, 234 | textarea { 235 | margin: 0; 236 | font-family: inherit; 237 | font-size: inherit; 238 | line-height: inherit; 239 | } 240 | 241 | button, 242 | input { 243 | overflow: visible; 244 | } 245 | 246 | button, 247 | select { 248 | text-transform: none; 249 | } 250 | 251 | button, 252 | html [type="button"], 253 | [type="reset"], 254 | [type="submit"] { 255 | -webkit-appearance: button; 256 | } 257 | 258 | button::-moz-focus-inner, 259 | [type="button"]::-moz-focus-inner, 260 | [type="reset"]::-moz-focus-inner, 261 | [type="submit"]::-moz-focus-inner { 262 | padding: 0; 263 | border-style: none; 264 | } 265 | 266 | input[type="radio"], 267 | input[type="checkbox"] { 268 | box-sizing: border-box; 269 | padding: 0; 270 | } 271 | 272 | input[type="date"], 273 | input[type="time"], 274 | input[type="datetime-local"], 275 | input[type="month"] { 276 | -webkit-appearance: listbox; 277 | } 278 | 279 | textarea { 280 | overflow: auto; 281 | resize: vertical; 282 | } 283 | 284 | fieldset { 285 | min-width: 0; 286 | padding: 0; 287 | margin: 0; 288 | border: 0; 289 | } 290 | 291 | legend { 292 | display: block; 293 | width: 100%; 294 | max-width: 100%; 295 | padding: 0; 296 | margin-bottom: .5rem; 297 | font-size: 1.5rem; 298 | line-height: inherit; 299 | color: inherit; 300 | white-space: normal; 301 | } 302 | 303 | progress { 304 | vertical-align: baseline; 305 | } 306 | 307 | [type="number"]::-webkit-inner-spin-button, 308 | [type="number"]::-webkit-outer-spin-button { 309 | height: auto; 310 | } 311 | 312 | [type="search"] { 313 | outline-offset: -2px; 314 | -webkit-appearance: none; 315 | } 316 | 317 | [type="search"]::-webkit-search-cancel-button, 318 | [type="search"]::-webkit-search-decoration { 319 | -webkit-appearance: none; 320 | } 321 | 322 | ::-webkit-file-upload-button { 323 | font: inherit; 324 | -webkit-appearance: button; 325 | } 326 | 327 | output { 328 | display: inline-block; 329 | } 330 | 331 | summary { 332 | display: list-item; 333 | } 334 | 335 | template { 336 | display: none; 337 | } 338 | 339 | [hidden] { 340 | display: none !important; 341 | } 342 | /*# sourceMappingURL=bootstrap-reboot.css.map */ -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/bootstrap/css/bootstrap-reboot.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v4.0.0-beta.2 (https://getbootstrap.com) 3 | * Copyright 2011-2017 The Bootstrap Authors 4 | * Copyright 2011-2017 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}[role=button],a,area,button,input:not([type=range]),label,select,summary,textarea{-ms-touch-action:manipulation;touch-action:manipulation}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#868e96;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item}template{display:none}[hidden]{display:none!important} 8 | /*# sourceMappingURL=bootstrap-reboot.min.css.map */ -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/datatables/dataTables.bootstrap4.css: -------------------------------------------------------------------------------- 1 | table.dataTable { 2 | clear: both; 3 | margin-top: 6px !important; 4 | margin-bottom: 6px !important; 5 | max-width: none !important; 6 | border-collapse: separate !important; 7 | } 8 | table.dataTable td, 9 | table.dataTable th { 10 | -webkit-box-sizing: content-box; 11 | box-sizing: content-box; 12 | } 13 | table.dataTable td.dataTables_empty, 14 | table.dataTable th.dataTables_empty { 15 | text-align: center; 16 | } 17 | table.dataTable.nowrap th, 18 | table.dataTable.nowrap td { 19 | white-space: nowrap; 20 | } 21 | 22 | div.dataTables_wrapper div.dataTables_length label { 23 | font-weight: normal; 24 | text-align: left; 25 | white-space: nowrap; 26 | } 27 | div.dataTables_wrapper div.dataTables_length select { 28 | width: 75px; 29 | display: inline-block; 30 | } 31 | div.dataTables_wrapper div.dataTables_filter { 32 | text-align: right; 33 | } 34 | div.dataTables_wrapper div.dataTables_filter label { 35 | font-weight: normal; 36 | white-space: nowrap; 37 | text-align: left; 38 | } 39 | div.dataTables_wrapper div.dataTables_filter input { 40 | margin-left: 0.5em; 41 | display: inline-block; 42 | width: auto; 43 | } 44 | div.dataTables_wrapper div.dataTables_info { 45 | padding-top: 0.85em; 46 | white-space: nowrap; 47 | } 48 | div.dataTables_wrapper div.dataTables_paginate { 49 | margin: 0; 50 | white-space: nowrap; 51 | text-align: right; 52 | } 53 | div.dataTables_wrapper div.dataTables_paginate ul.pagination { 54 | margin: 2px 0; 55 | white-space: nowrap; 56 | justify-content: flex-end; 57 | } 58 | div.dataTables_wrapper div.dataTables_processing { 59 | position: absolute; 60 | top: 50%; 61 | left: 50%; 62 | width: 200px; 63 | margin-left: -100px; 64 | margin-top: -26px; 65 | text-align: center; 66 | padding: 1em 0; 67 | } 68 | 69 | table.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting, 70 | table.dataTable thead > tr > td.sorting_asc, 71 | table.dataTable thead > tr > td.sorting_desc, 72 | table.dataTable thead > tr > td.sorting { 73 | padding-right: 30px; 74 | } 75 | table.dataTable thead > tr > th:active, 76 | table.dataTable thead > tr > td:active { 77 | outline: none; 78 | } 79 | table.dataTable thead .sorting, 80 | table.dataTable thead .sorting_asc, 81 | table.dataTable thead .sorting_desc, 82 | table.dataTable thead .sorting_asc_disabled, 83 | table.dataTable thead .sorting_desc_disabled { 84 | cursor: pointer; 85 | position: relative; 86 | } 87 | table.dataTable thead .sorting:before, table.dataTable thead .sorting:after, 88 | table.dataTable thead .sorting_asc:before, 89 | table.dataTable thead .sorting_asc:after, 90 | table.dataTable thead .sorting_desc:before, 91 | table.dataTable thead .sorting_desc:after, 92 | table.dataTable thead .sorting_asc_disabled:before, 93 | table.dataTable thead .sorting_asc_disabled:after, 94 | table.dataTable thead .sorting_desc_disabled:before, 95 | table.dataTable thead .sorting_desc_disabled:after { 96 | position: absolute; 97 | bottom: 0.9em; 98 | display: block; 99 | opacity: 0.3; 100 | } 101 | table.dataTable thead .sorting:before, 102 | table.dataTable thead .sorting_asc:before, 103 | table.dataTable thead .sorting_desc:before, 104 | table.dataTable thead .sorting_asc_disabled:before, 105 | table.dataTable thead .sorting_desc_disabled:before { 106 | right: 1em; 107 | content: "\2191"; 108 | } 109 | table.dataTable thead .sorting:after, 110 | table.dataTable thead .sorting_asc:after, 111 | table.dataTable thead .sorting_desc:after, 112 | table.dataTable thead .sorting_asc_disabled:after, 113 | table.dataTable thead .sorting_desc_disabled:after { 114 | right: 0.5em; 115 | content: "\2193"; 116 | } 117 | table.dataTable thead .sorting_asc:before, 118 | table.dataTable thead .sorting_desc:after { 119 | opacity: 1; 120 | } 121 | table.dataTable thead .sorting_asc_disabled:before, 122 | table.dataTable thead .sorting_desc_disabled:after { 123 | opacity: 0; 124 | } 125 | 126 | div.dataTables_scrollHead table.dataTable { 127 | margin-bottom: 0 !important; 128 | } 129 | 130 | div.dataTables_scrollBody table { 131 | border-top: none; 132 | margin-top: 0 !important; 133 | margin-bottom: 0 !important; 134 | } 135 | div.dataTables_scrollBody table thead .sorting:after, 136 | div.dataTables_scrollBody table thead .sorting_asc:after, 137 | div.dataTables_scrollBody table thead .sorting_desc:after { 138 | display: none; 139 | } 140 | div.dataTables_scrollBody table tbody tr:first-child th, 141 | div.dataTables_scrollBody table tbody tr:first-child td { 142 | border-top: none; 143 | } 144 | 145 | div.dataTables_scrollFoot > .dataTables_scrollFootInner { 146 | box-sizing: content-box; 147 | } 148 | div.dataTables_scrollFoot > .dataTables_scrollFootInner > table { 149 | margin-top: 0 !important; 150 | border-top: none; 151 | } 152 | 153 | @media screen and (max-width: 767px) { 154 | div.dataTables_wrapper div.dataTables_length, 155 | div.dataTables_wrapper div.dataTables_filter, 156 | div.dataTables_wrapper div.dataTables_info, 157 | div.dataTables_wrapper div.dataTables_paginate { 158 | text-align: center; 159 | } 160 | } 161 | table.dataTable.table-sm > thead > tr > th { 162 | padding-right: 20px; 163 | } 164 | table.dataTable.table-sm .sorting:before, 165 | table.dataTable.table-sm .sorting_asc:before, 166 | table.dataTable.table-sm .sorting_desc:before { 167 | top: 5px; 168 | right: 0.85em; 169 | } 170 | table.dataTable.table-sm .sorting:after, 171 | table.dataTable.table-sm .sorting_asc:after, 172 | table.dataTable.table-sm .sorting_desc:after { 173 | top: 5px; 174 | } 175 | 176 | table.table-bordered.dataTable th, 177 | table.table-bordered.dataTable td { 178 | border-left-width: 0; 179 | } 180 | table.table-bordered.dataTable th:last-child, table.table-bordered.dataTable th:last-child, 181 | table.table-bordered.dataTable td:last-child, 182 | table.table-bordered.dataTable td:last-child { 183 | border-right-width: 0; 184 | } 185 | table.table-bordered.dataTable tbody th, 186 | table.table-bordered.dataTable tbody td { 187 | border-bottom-width: 0; 188 | } 189 | 190 | div.dataTables_scrollHead table.table-bordered { 191 | border-bottom-width: 0; 192 | } 193 | 194 | div.table-responsive > div.dataTables_wrapper > div.row { 195 | margin: 0; 196 | } 197 | div.table-responsive > div.dataTables_wrapper > div.row > div[class^="col-"]:first-child { 198 | padding-left: 0; 199 | } 200 | div.table-responsive > div.dataTables_wrapper > div.row > div[class^="col-"]:last-child { 201 | padding-right: 0; 202 | } 203 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/datatables/dataTables.bootstrap4.js: -------------------------------------------------------------------------------- 1 | /*! DataTables Bootstrap 3 integration 2 | * ©2011-2015 SpryMedia Ltd - datatables.net/license 3 | */ 4 | 5 | /** 6 | * DataTables integration for Bootstrap 3. This requires Bootstrap 3 and 7 | * DataTables 1.10 or newer. 8 | * 9 | * This file sets the defaults and adds options to DataTables to style its 10 | * controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap 11 | * for further information. 12 | */ 13 | (function( factory ){ 14 | if ( typeof define === 'function' && define.amd ) { 15 | // AMD 16 | define( ['jquery', 'datatables.net'], function ( $ ) { 17 | return factory( $, window, document ); 18 | } ); 19 | } 20 | else if ( typeof exports === 'object' ) { 21 | // CommonJS 22 | module.exports = function (root, $) { 23 | if ( ! root ) { 24 | root = window; 25 | } 26 | 27 | if ( ! $ || ! $.fn.dataTable ) { 28 | // Require DataTables, which attaches to jQuery, including 29 | // jQuery if needed and have a $ property so we can access the 30 | // jQuery object that is used 31 | $ = require('datatables.net')(root, $).$; 32 | } 33 | 34 | return factory( $, root, root.document ); 35 | }; 36 | } 37 | else { 38 | // Browser 39 | factory( jQuery, window, document ); 40 | } 41 | }(function( $, window, document, undefined ) { 42 | 'use strict'; 43 | var DataTable = $.fn.dataTable; 44 | 45 | 46 | /* Set the defaults for DataTables initialisation */ 47 | $.extend( true, DataTable.defaults, { 48 | dom: 49 | "<'row'<'col-sm-12 col-md-6'l><'col-sm-12 col-md-6'f>>" + 50 | "<'row'<'col-sm-12'tr>>" + 51 | "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", 52 | renderer: 'bootstrap' 53 | } ); 54 | 55 | 56 | /* Default class modification */ 57 | $.extend( DataTable.ext.classes, { 58 | sWrapper: "dataTables_wrapper container-fluid dt-bootstrap4", 59 | sFilterInput: "form-control form-control-sm", 60 | sLengthSelect: "form-control form-control-sm", 61 | sProcessing: "dataTables_processing card", 62 | sPageButton: "paginate_button page-item" 63 | } ); 64 | 65 | 66 | /* Bootstrap paging button renderer */ 67 | DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, buttons, page, pages ) { 68 | var api = new DataTable.Api( settings ); 69 | var classes = settings.oClasses; 70 | var lang = settings.oLanguage.oPaginate; 71 | var aria = settings.oLanguage.oAria.paginate || {}; 72 | var btnDisplay, btnClass, counter=0; 73 | 74 | var attach = function( container, buttons ) { 75 | var i, ien, node, button; 76 | var clickHandler = function ( e ) { 77 | e.preventDefault(); 78 | if ( !$(e.currentTarget).hasClass('disabled') && api.page() != e.data.action ) { 79 | api.page( e.data.action ).draw( 'page' ); 80 | } 81 | }; 82 | 83 | for ( i=0, ien=buttons.length ; i 0 ? 102 | '' : ' disabled'); 103 | break; 104 | 105 | case 'previous': 106 | btnDisplay = lang.sPrevious; 107 | btnClass = button + (page > 0 ? 108 | '' : ' disabled'); 109 | break; 110 | 111 | case 'next': 112 | btnDisplay = lang.sNext; 113 | btnClass = button + (page < pages-1 ? 114 | '' : ' disabled'); 115 | break; 116 | 117 | case 'last': 118 | btnDisplay = lang.sLast; 119 | btnClass = button + (page < pages-1 ? 120 | '' : ' disabled'); 121 | break; 122 | 123 | default: 124 | btnDisplay = button + 1; 125 | btnClass = page === button ? 126 | 'active' : ''; 127 | break; 128 | } 129 | 130 | if ( btnDisplay ) { 131 | node = $('
  • ', { 132 | 'class': classes.sPageButton+' '+btnClass, 133 | 'id': idx === 0 && typeof button === 'string' ? 134 | settings.sTableId +'_'+ button : 135 | null 136 | } ) 137 | .append( $('', { 138 | 'href': '#', 139 | 'aria-controls': settings.sTableId, 140 | 'aria-label': aria[ button ], 141 | 'data-dt-idx': counter, 142 | 'tabindex': settings.iTabIndex, 143 | 'class': 'page-link' 144 | } ) 145 | .html( btnDisplay ) 146 | ) 147 | .appendTo( container ); 148 | 149 | settings.oApi._fnBindAction( 150 | node, {action: button}, clickHandler 151 | ); 152 | 153 | counter++; 154 | } 155 | } 156 | } 157 | }; 158 | 159 | // IE9 throws an 'unknown error' if document.activeElement is used 160 | // inside an iframe or frame. 161 | var activeEl; 162 | 163 | try { 164 | // Because this approach is destroying and recreating the paging 165 | // elements, focus is lost on the select button which is bad for 166 | // accessibility. So we want to restore focus once the draw has 167 | // completed 168 | activeEl = $(host).find(document.activeElement).data('dt-idx'); 169 | } 170 | catch (e) {} 171 | 172 | attach( 173 | $(host).empty().html('
      ').children('ul'), 174 | buttons 175 | ); 176 | 177 | if ( activeEl !== undefined ) { 178 | $(host).find( '[data-dt-idx='+activeEl+']' ).focus(); 179 | } 180 | }; 181 | 182 | 183 | return DataTable; 184 | })); 185 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audit4j/audit4j-microservice/eed7a9999a84706a3b649e3f78d3ff13af1a1cd8/src/main/resources/webroot/vendor/font-awesome/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audit4j/audit4j-microservice/eed7a9999a84706a3b649e3f78d3ff13af1a1cd8/src/main/resources/webroot/vendor/font-awesome/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audit4j/audit4j-microservice/eed7a9999a84706a3b649e3f78d3ff13af1a1cd8/src/main/resources/webroot/vendor/font-awesome/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audit4j/audit4j-microservice/eed7a9999a84706a3b649e3f78d3ff13af1a1cd8/src/main/resources/webroot/vendor/font-awesome/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audit4j/audit4j-microservice/eed7a9999a84706a3b649e3f78d3ff13af1a1cd8/src/main/resources/webroot/vendor/font-awesome/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/less/animated.less: -------------------------------------------------------------------------------- 1 | // Animated Icons 2 | // -------------------------- 3 | 4 | .@{fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | .@{fa-css-prefix}-pulse { 10 | -webkit-animation: fa-spin 1s infinite steps(8); 11 | animation: fa-spin 1s infinite steps(8); 12 | } 13 | 14 | @-webkit-keyframes fa-spin { 15 | 0% { 16 | -webkit-transform: rotate(0deg); 17 | transform: rotate(0deg); 18 | } 19 | 100% { 20 | -webkit-transform: rotate(359deg); 21 | transform: rotate(359deg); 22 | } 23 | } 24 | 25 | @keyframes fa-spin { 26 | 0% { 27 | -webkit-transform: rotate(0deg); 28 | transform: rotate(0deg); 29 | } 30 | 100% { 31 | -webkit-transform: rotate(359deg); 32 | transform: rotate(359deg); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/less/bordered-pulled.less: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em @fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .@{fa-css-prefix}-pull-left { float: left; } 11 | .@{fa-css-prefix}-pull-right { float: right; } 12 | 13 | .@{fa-css-prefix} { 14 | &.@{fa-css-prefix}-pull-left { margin-right: .3em; } 15 | &.@{fa-css-prefix}-pull-right { margin-left: .3em; } 16 | } 17 | 18 | /* Deprecated as of 4.4.0 */ 19 | .pull-right { float: right; } 20 | .pull-left { float: left; } 21 | 22 | .@{fa-css-prefix} { 23 | &.pull-left { margin-right: .3em; } 24 | &.pull-right { margin-left: .3em; } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/less/core.less: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/less/fixed-width.less: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .@{fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/less/font-awesome.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables.less"; 7 | @import "mixins.less"; 8 | @import "path.less"; 9 | @import "core.less"; 10 | @import "larger.less"; 11 | @import "fixed-width.less"; 12 | @import "list.less"; 13 | @import "bordered-pulled.less"; 14 | @import "animated.less"; 15 | @import "rotated-flipped.less"; 16 | @import "stacked.less"; 17 | @import "icons.less"; 18 | @import "screen-reader.less"; 19 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/less/larger.less: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .@{fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .@{fa-css-prefix}-2x { font-size: 2em; } 11 | .@{fa-css-prefix}-3x { font-size: 3em; } 12 | .@{fa-css-prefix}-4x { font-size: 4em; } 13 | .@{fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/less/list.less: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: @fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .@{fa-css-prefix}-li { 11 | position: absolute; 12 | left: -@fa-li-width; 13 | width: @fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.@{fa-css-prefix}-lg { 17 | left: (-@fa-li-width + (4em / 14)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/less/mixins.less: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | .fa-icon() { 5 | display: inline-block; 6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | 14 | .fa-icon-rotate(@degrees, @rotation) { 15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})"; 16 | -webkit-transform: rotate(@degrees); 17 | -ms-transform: rotate(@degrees); 18 | transform: rotate(@degrees); 19 | } 20 | 21 | .fa-icon-flip(@horiz, @vert, @rotation) { 22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)"; 23 | -webkit-transform: scale(@horiz, @vert); 24 | -ms-transform: scale(@horiz, @vert); 25 | transform: scale(@horiz, @vert); 26 | } 27 | 28 | 29 | // Only display content to screen readers. A la Bootstrap 4. 30 | // 31 | // See: http://a11yproject.com/posts/how-to-hide-content/ 32 | 33 | .sr-only() { 34 | position: absolute; 35 | width: 1px; 36 | height: 1px; 37 | padding: 0; 38 | margin: -1px; 39 | overflow: hidden; 40 | clip: rect(0,0,0,0); 41 | border: 0; 42 | } 43 | 44 | // Use in conjunction with .sr-only to only display content when it's focused. 45 | // 46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 47 | // 48 | // Credit: HTML5 Boilerplate 49 | 50 | .sr-only-focusable() { 51 | &:active, 52 | &:focus { 53 | position: static; 54 | width: auto; 55 | height: auto; 56 | margin: 0; 57 | overflow: visible; 58 | clip: auto; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/less/path.less: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}'); 7 | src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'), 8 | url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'), 9 | url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'), 10 | url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'), 11 | url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg'); 12 | // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/less/rotated-flipped.less: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); } 5 | .@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); } 6 | .@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); } 7 | 8 | .@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); } 9 | .@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .@{fa-css-prefix}-rotate-90, 15 | :root .@{fa-css-prefix}-rotate-180, 16 | :root .@{fa-css-prefix}-rotate-270, 17 | :root .@{fa-css-prefix}-flip-horizontal, 18 | :root .@{fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/less/screen-reader.less: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { .sr-only(); } 5 | .sr-only-focusable { .sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/less/stacked.less: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .@{fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .@{fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .@{fa-css-prefix}-inverse { color: @fa-inverse; } 21 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/scss/_animated.scss: -------------------------------------------------------------------------------- 1 | // Spinning Icons 2 | // -------------------------- 3 | 4 | .#{$fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | .#{$fa-css-prefix}-pulse { 10 | -webkit-animation: fa-spin 1s infinite steps(8); 11 | animation: fa-spin 1s infinite steps(8); 12 | } 13 | 14 | @-webkit-keyframes fa-spin { 15 | 0% { 16 | -webkit-transform: rotate(0deg); 17 | transform: rotate(0deg); 18 | } 19 | 100% { 20 | -webkit-transform: rotate(359deg); 21 | transform: rotate(359deg); 22 | } 23 | } 24 | 25 | @keyframes fa-spin { 26 | 0% { 27 | -webkit-transform: rotate(0deg); 28 | transform: rotate(0deg); 29 | } 30 | 100% { 31 | -webkit-transform: rotate(359deg); 32 | transform: rotate(359deg); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/scss/_bordered-pulled.scss: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em $fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .#{$fa-css-prefix}-pull-left { float: left; } 11 | .#{$fa-css-prefix}-pull-right { float: right; } 12 | 13 | .#{$fa-css-prefix} { 14 | &.#{$fa-css-prefix}-pull-left { margin-right: .3em; } 15 | &.#{$fa-css-prefix}-pull-right { margin-left: .3em; } 16 | } 17 | 18 | /* Deprecated as of 4.4.0 */ 19 | .pull-right { float: right; } 20 | .pull-left { float: left; } 21 | 22 | .#{$fa-css-prefix} { 23 | &.pull-left { margin-right: .3em; } 24 | &.pull-right { margin-left: .3em; } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/scss/_core.scss: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/scss/_fixed-width.scss: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .#{$fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/scss/_larger.scss: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .#{$fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .#{$fa-css-prefix}-2x { font-size: 2em; } 11 | .#{$fa-css-prefix}-3x { font-size: 3em; } 12 | .#{$fa-css-prefix}-4x { font-size: 4em; } 13 | .#{$fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/scss/_list.scss: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: $fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .#{$fa-css-prefix}-li { 11 | position: absolute; 12 | left: -$fa-li-width; 13 | width: $fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.#{$fa-css-prefix}-lg { 17 | left: -$fa-li-width + (4em / 14); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/scss/_mixins.scss: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | @mixin fa-icon() { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | 14 | @mixin fa-icon-rotate($degrees, $rotation) { 15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})"; 16 | -webkit-transform: rotate($degrees); 17 | -ms-transform: rotate($degrees); 18 | transform: rotate($degrees); 19 | } 20 | 21 | @mixin fa-icon-flip($horiz, $vert, $rotation) { 22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)"; 23 | -webkit-transform: scale($horiz, $vert); 24 | -ms-transform: scale($horiz, $vert); 25 | transform: scale($horiz, $vert); 26 | } 27 | 28 | 29 | // Only display content to screen readers. A la Bootstrap 4. 30 | // 31 | // See: http://a11yproject.com/posts/how-to-hide-content/ 32 | 33 | @mixin sr-only { 34 | position: absolute; 35 | width: 1px; 36 | height: 1px; 37 | padding: 0; 38 | margin: -1px; 39 | overflow: hidden; 40 | clip: rect(0,0,0,0); 41 | border: 0; 42 | } 43 | 44 | // Use in conjunction with .sr-only to only display content when it's focused. 45 | // 46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 47 | // 48 | // Credit: HTML5 Boilerplate 49 | 50 | @mixin sr-only-focusable { 51 | &:active, 52 | &:focus { 53 | position: static; 54 | width: auto; 55 | height: auto; 56 | margin: 0; 57 | overflow: visible; 58 | clip: auto; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/scss/_path.scss: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}'); 7 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), 8 | url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'), 9 | url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), 10 | url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), 11 | url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg'); 12 | // src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/scss/_rotated-flipped.scss: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } 5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } 6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } 7 | 8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } 9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .#{$fa-css-prefix}-rotate-90, 15 | :root .#{$fa-css-prefix}-rotate-180, 16 | :root .#{$fa-css-prefix}-rotate-270, 17 | :root .#{$fa-css-prefix}-flip-horizontal, 18 | :root .#{$fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/scss/_screen-reader.scss: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { @include sr-only(); } 5 | .sr-only-focusable { @include sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/scss/_stacked.scss: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .#{$fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .#{$fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .#{$fa-css-prefix}-inverse { color: $fa-inverse; } 21 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/font-awesome/scss/font-awesome.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables"; 7 | @import "mixins"; 8 | @import "path"; 9 | @import "core"; 10 | @import "larger"; 11 | @import "fixed-width"; 12 | @import "list"; 13 | @import "bordered-pulled"; 14 | @import "animated"; 15 | @import "rotated-flipped"; 16 | @import "stacked"; 17 | @import "icons"; 18 | @import "screen-reader"; 19 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/jquery-easing/jquery.easing.compatibility.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Easing Compatibility v1 - http://gsgd.co.uk/sandbox/jquery/easing 3 | * 4 | * Adds compatibility for applications that use the pre 1.2 easing names 5 | * 6 | * Copyright (c) 2007 George Smith 7 | * Licensed under the MIT License: 8 | * http://www.opensource.org/licenses/mit-license.php 9 | */ 10 | 11 | (function($){ 12 | $.extend( $.easing, 13 | { 14 | easeIn: function (x, t, b, c, d) { 15 | return $.easing.easeInQuad(x, t, b, c, d); 16 | }, 17 | easeOut: function (x, t, b, c, d) { 18 | return $.easing.easeOutQuad(x, t, b, c, d); 19 | }, 20 | easeInOut: function (x, t, b, c, d) { 21 | return $.easing.easeInOutQuad(x, t, b, c, d); 22 | }, 23 | expoin: function(x, t, b, c, d) { 24 | return $.easing.easeInExpo(x, t, b, c, d); 25 | }, 26 | expoout: function(x, t, b, c, d) { 27 | return $.easing.easeOutExpo(x, t, b, c, d); 28 | }, 29 | expoinout: function(x, t, b, c, d) { 30 | return $.easing.easeInOutExpo(x, t, b, c, d); 31 | }, 32 | bouncein: function(x, t, b, c, d) { 33 | return $.easing.easeInBounce(x, t, b, c, d); 34 | }, 35 | bounceout: function(x, t, b, c, d) { 36 | return $.easing.easeOutBounce(x, t, b, c, d); 37 | }, 38 | bounceinout: function(x, t, b, c, d) { 39 | return $.easing.easeInOutBounce(x, t, b, c, d); 40 | }, 41 | elasin: function(x, t, b, c, d) { 42 | return $.easing.easeInElastic(x, t, b, c, d); 43 | }, 44 | elasout: function(x, t, b, c, d) { 45 | return $.easing.easeOutElastic(x, t, b, c, d); 46 | }, 47 | elasinout: function(x, t, b, c, d) { 48 | return $.easing.easeInOutElastic(x, t, b, c, d); 49 | }, 50 | backin: function(x, t, b, c, d) { 51 | return $.easing.easeInBack(x, t, b, c, d); 52 | }, 53 | backout: function(x, t, b, c, d) { 54 | return $.easing.easeOutBack(x, t, b, c, d); 55 | }, 56 | backinout: function(x, t, b, c, d) { 57 | return $.easing.easeInOutBack(x, t, b, c, d); 58 | } 59 | });})(jQuery); 60 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/jquery-easing/jquery.easing.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Easing v1.4.1 - http://gsgd.co.uk/sandbox/jquery/easing/ 3 | * Open source under the BSD License. 4 | * Copyright © 2008 George McGinley Smith 5 | * All rights reserved. 6 | * https://raw.github.com/gdsmith/jquery-easing/master/LICENSE 7 | */ 8 | 9 | (function (factory) { 10 | if (typeof define === "function" && define.amd) { 11 | define(['jquery'], function ($) { 12 | return factory($); 13 | }); 14 | } else if (typeof module === "object" && typeof module.exports === "object") { 15 | exports = factory(require('jquery')); 16 | } else { 17 | factory(jQuery); 18 | } 19 | })(function($){ 20 | 21 | // Preserve the original jQuery "swing" easing as "jswing" 22 | $.easing.jswing = $.easing.swing; 23 | 24 | var pow = Math.pow, 25 | sqrt = Math.sqrt, 26 | sin = Math.sin, 27 | cos = Math.cos, 28 | PI = Math.PI, 29 | c1 = 1.70158, 30 | c2 = c1 * 1.525, 31 | c3 = c1 + 1, 32 | c4 = ( 2 * PI ) / 3, 33 | c5 = ( 2 * PI ) / 4.5; 34 | 35 | // x is the fraction of animation progress, in the range 0..1 36 | function bounceOut(x) { 37 | var n1 = 7.5625, 38 | d1 = 2.75; 39 | if ( x < 1/d1 ) { 40 | return n1*x*x; 41 | } else if ( x < 2/d1 ) { 42 | return n1*(x-=(1.5/d1))*x + 0.75; 43 | } else if ( x < 2.5/d1 ) { 44 | return n1*(x-=(2.25/d1))*x + 0.9375; 45 | } else { 46 | return n1*(x-=(2.625/d1))*x + 0.984375; 47 | } 48 | } 49 | 50 | $.extend( $.easing, 51 | { 52 | def: 'easeOutQuad', 53 | swing: function (x) { 54 | return $.easing[$.easing.def](x); 55 | }, 56 | easeInQuad: function (x) { 57 | return x * x; 58 | }, 59 | easeOutQuad: function (x) { 60 | return 1 - ( 1 - x ) * ( 1 - x ); 61 | }, 62 | easeInOutQuad: function (x) { 63 | return x < 0.5 ? 64 | 2 * x * x : 65 | 1 - pow( -2 * x + 2, 2 ) / 2; 66 | }, 67 | easeInCubic: function (x) { 68 | return x * x * x; 69 | }, 70 | easeOutCubic: function (x) { 71 | return 1 - pow( 1 - x, 3 ); 72 | }, 73 | easeInOutCubic: function (x) { 74 | return x < 0.5 ? 75 | 4 * x * x * x : 76 | 1 - pow( -2 * x + 2, 3 ) / 2; 77 | }, 78 | easeInQuart: function (x) { 79 | return x * x * x * x; 80 | }, 81 | easeOutQuart: function (x) { 82 | return 1 - pow( 1 - x, 4 ); 83 | }, 84 | easeInOutQuart: function (x) { 85 | return x < 0.5 ? 86 | 8 * x * x * x * x : 87 | 1 - pow( -2 * x + 2, 4 ) / 2; 88 | }, 89 | easeInQuint: function (x) { 90 | return x * x * x * x * x; 91 | }, 92 | easeOutQuint: function (x) { 93 | return 1 - pow( 1 - x, 5 ); 94 | }, 95 | easeInOutQuint: function (x) { 96 | return x < 0.5 ? 97 | 16 * x * x * x * x * x : 98 | 1 - pow( -2 * x + 2, 5 ) / 2; 99 | }, 100 | easeInSine: function (x) { 101 | return 1 - cos( x * PI/2 ); 102 | }, 103 | easeOutSine: function (x) { 104 | return sin( x * PI/2 ); 105 | }, 106 | easeInOutSine: function (x) { 107 | return -( cos( PI * x ) - 1 ) / 2; 108 | }, 109 | easeInExpo: function (x) { 110 | return x === 0 ? 0 : pow( 2, 10 * x - 10 ); 111 | }, 112 | easeOutExpo: function (x) { 113 | return x === 1 ? 1 : 1 - pow( 2, -10 * x ); 114 | }, 115 | easeInOutExpo: function (x) { 116 | return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ? 117 | pow( 2, 20 * x - 10 ) / 2 : 118 | ( 2 - pow( 2, -20 * x + 10 ) ) / 2; 119 | }, 120 | easeInCirc: function (x) { 121 | return 1 - sqrt( 1 - pow( x, 2 ) ); 122 | }, 123 | easeOutCirc: function (x) { 124 | return sqrt( 1 - pow( x - 1, 2 ) ); 125 | }, 126 | easeInOutCirc: function (x) { 127 | return x < 0.5 ? 128 | ( 1 - sqrt( 1 - pow( 2 * x, 2 ) ) ) / 2 : 129 | ( sqrt( 1 - pow( -2 * x + 2, 2 ) ) + 1 ) / 2; 130 | }, 131 | easeInElastic: function (x) { 132 | return x === 0 ? 0 : x === 1 ? 1 : 133 | -pow( 2, 10 * x - 10 ) * sin( ( x * 10 - 10.75 ) * c4 ); 134 | }, 135 | easeOutElastic: function (x) { 136 | return x === 0 ? 0 : x === 1 ? 1 : 137 | pow( 2, -10 * x ) * sin( ( x * 10 - 0.75 ) * c4 ) + 1; 138 | }, 139 | easeInOutElastic: function (x) { 140 | return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ? 141 | -( pow( 2, 20 * x - 10 ) * sin( ( 20 * x - 11.125 ) * c5 )) / 2 : 142 | pow( 2, -20 * x + 10 ) * sin( ( 20 * x - 11.125 ) * c5 ) / 2 + 1; 143 | }, 144 | easeInBack: function (x) { 145 | return c3 * x * x * x - c1 * x * x; 146 | }, 147 | easeOutBack: function (x) { 148 | return 1 + c3 * pow( x - 1, 3 ) + c1 * pow( x - 1, 2 ); 149 | }, 150 | easeInOutBack: function (x) { 151 | return x < 0.5 ? 152 | ( pow( 2 * x, 2 ) * ( ( c2 + 1 ) * 2 * x - c2 ) ) / 2 : 153 | ( pow( 2 * x - 2, 2 ) *( ( c2 + 1 ) * ( x * 2 - 2 ) + c2 ) + 2 ) / 2; 154 | }, 155 | easeInBounce: function (x) { 156 | return 1 - bounceOut( 1 - x ); 157 | }, 158 | easeOutBounce: bounceOut, 159 | easeInOutBounce: function (x) { 160 | return x < 0.5 ? 161 | ( 1 - bounceOut( 1 - 2 * x ) ) / 2 : 162 | ( 1 + bounceOut( 2 * x - 1 ) ) / 2; 163 | } 164 | }); 165 | 166 | }); 167 | -------------------------------------------------------------------------------- /src/main/resources/webroot/vendor/jquery-easing/jquery.easing.min.js: -------------------------------------------------------------------------------- 1 | (function(factory){if(typeof define==="function"&&define.amd){define(["jquery"],function($){return factory($)})}else if(typeof module==="object"&&typeof module.exports==="object"){exports=factory(require("jquery"))}else{factory(jQuery)}})(function($){$.easing.jswing=$.easing.swing;var pow=Math.pow,sqrt=Math.sqrt,sin=Math.sin,cos=Math.cos,PI=Math.PI,c1=1.70158,c2=c1*1.525,c3=c1+1,c4=2*PI/3,c5=2*PI/4.5;function bounceOut(x){var n1=7.5625,d1=2.75;if(x<1/d1){return n1*x*x}else if(x<2/d1){return n1*(x-=1.5/d1)*x+.75}else if(x<2.5/d1){return n1*(x-=2.25/d1)*x+.9375}else{return n1*(x-=2.625/d1)*x+.984375}}$.extend($.easing,{def:"easeOutQuad",swing:function(x){return $.easing[$.easing.def](x)},easeInQuad:function(x){return x*x},easeOutQuad:function(x){return 1-(1-x)*(1-x)},easeInOutQuad:function(x){return x<.5?2*x*x:1-pow(-2*x+2,2)/2},easeInCubic:function(x){return x*x*x},easeOutCubic:function(x){return 1-pow(1-x,3)},easeInOutCubic:function(x){return x<.5?4*x*x*x:1-pow(-2*x+2,3)/2},easeInQuart:function(x){return x*x*x*x},easeOutQuart:function(x){return 1-pow(1-x,4)},easeInOutQuart:function(x){return x<.5?8*x*x*x*x:1-pow(-2*x+2,4)/2},easeInQuint:function(x){return x*x*x*x*x},easeOutQuint:function(x){return 1-pow(1-x,5)},easeInOutQuint:function(x){return x<.5?16*x*x*x*x*x:1-pow(-2*x+2,5)/2},easeInSine:function(x){return 1-cos(x*PI/2)},easeOutSine:function(x){return sin(x*PI/2)},easeInOutSine:function(x){return-(cos(PI*x)-1)/2},easeInExpo:function(x){return x===0?0:pow(2,10*x-10)},easeOutExpo:function(x){return x===1?1:1-pow(2,-10*x)},easeInOutExpo:function(x){return x===0?0:x===1?1:x<.5?pow(2,20*x-10)/2:(2-pow(2,-20*x+10))/2},easeInCirc:function(x){return 1-sqrt(1-pow(x,2))},easeOutCirc:function(x){return sqrt(1-pow(x-1,2))},easeInOutCirc:function(x){return x<.5?(1-sqrt(1-pow(2*x,2)))/2:(sqrt(1-pow(-2*x+2,2))+1)/2},easeInElastic:function(x){return x===0?0:x===1?1:-pow(2,10*x-10)*sin((x*10-10.75)*c4)},easeOutElastic:function(x){return x===0?0:x===1?1:pow(2,-10*x)*sin((x*10-.75)*c4)+1},easeInOutElastic:function(x){return x===0?0:x===1?1:x<.5?-(pow(2,20*x-10)*sin((20*x-11.125)*c5))/2:pow(2,-20*x+10)*sin((20*x-11.125)*c5)/2+1},easeInBack:function(x){return c3*x*x*x-c1*x*x},easeOutBack:function(x){return 1+c3*pow(x-1,3)+c1*pow(x-1,2)},easeInOutBack:function(x){return x<.5?pow(2*x,2)*((c2+1)*2*x-c2)/2:(pow(2*x-2,2)*((c2+1)*(x*2-2)+c2)+2)/2},easeInBounce:function(x){return 1-bounceOut(1-x)},easeOutBounce:bounceOut,easeInOutBounce:function(x){return x<.5?(1-bounceOut(1-2*x))/2:(1+bounceOut(2*x-1))/2}})}); -------------------------------------------------------------------------------- /src/test/java/org/audit4j/microservice/SmokeTest.java: -------------------------------------------------------------------------------- 1 | package org.audit4j.microservice; 2 | 3 | import org.apache.thrift.TException; 4 | import org.apache.thrift.protocol.TBinaryProtocol; 5 | import org.apache.thrift.protocol.TProtocol; 6 | import org.apache.thrift.transport.TSocket; 7 | import org.apache.thrift.transport.TTransport; 8 | import org.audit4j.microservice.transport.thrift.TAck; 9 | import org.audit4j.microservice.transport.thrift.TAuditEvent; 10 | import org.audit4j.microservice.transport.thrift.TAuditService; 11 | 12 | public class SmokeTest { 13 | 14 | public static void main(String [] args) { 15 | try { 16 | TTransport transport; 17 | 18 | transport = new TSocket("localhost", 9092); 19 | transport.open(); 20 | 21 | 22 | // Uncomment below lines for secure RPC communication 23 | // TSSLTransportFactory.TSSLTransportParameters params = 24 | // new TSSLTransportFactory.TSSLTransportParameters(); 25 | // params.setTrustStore("lib/truststore.jks", "123456"); 26 | 27 | // transport = TSSLTransportFactory.getClientSocket("localhost", 9091, 10000, params); 28 | 29 | 30 | TProtocol protocol = new TBinaryProtocol(transport); 31 | TAuditService.Client client = new TAuditService.Client(protocol); 32 | 33 | perform(client); 34 | 35 | transport.close(); 36 | } catch (TException x) { 37 | x.printStackTrace(); 38 | } 39 | } 40 | 41 | private static void perform(TAuditService.Client client) throws TException 42 | { 43 | TAuditEvent event = new TAuditEvent(); 44 | event.setAction("aaa"); 45 | event.setActor("Dumb"); 46 | event.setTimestamp("12/07/1017"); 47 | event.setTimestampFormat("dd/MM/yyyy"); 48 | event.setUuid(12); 49 | 50 | TAck ack = client.audit(event); 51 | System.out.println("Ack=====" + ack.getCode()); 52 | } 53 | } 54 | --------------------------------------------------------------------------------