Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9b6e188df8 | |||
| ee6b2a8919 | |||
| 0f551bd5c7 | |||
| 109c09d2a3 | |||
| 1fd3b689c8 | |||
| bab7e02b02 | |||
| 69e8b767ff |
@@ -2,6 +2,28 @@
|
||||
|
||||
|
||||
|
||||
## Database Configuration
|
||||
|
||||
### Development Database (H2 Console)
|
||||
- **Profile**: `dev`
|
||||
- **Database Type**: H2 (File-based, embedded)
|
||||
- **JDBC URL**: `jdbc:h2:file:./build/h2db/db/sisvietnamvn`
|
||||
- **Username**: `sisvietnamvn`
|
||||
- **Password**: *(leave blank)*
|
||||
- **Console Access**: [http://localhost:8080/h2-console](http://localhost:8080/h2-console) (requires app running in dev profile)
|
||||
- **Config File**: [application-dev.yml](file:///d:/website_sisvietnam_moi/website_sisvietnam.vn/sisvietnamvn/src/main/resources/config/application-dev.yml)
|
||||
|
||||
### Production Database
|
||||
- **Profile**: `prod`
|
||||
- **Database Type**: Oracle Database
|
||||
- **JDBC URL**: `jdbc:oracle:thin:@localhost:1521:xe`
|
||||
- **Username**: `sisvietnamvn`
|
||||
- **Config File**: [application-prod.yml](file:///d:/website_sisvietnam_moi/website_sisvietnam.vn/sisvietnamvn/src/main/resources/config/application-prod.yml)
|
||||
|
||||
### Schema Management
|
||||
- **Tool**: Liquibase
|
||||
- **Changelog Folder**: [src/main/resources/config/liquibase/](file:///d:/website_sisvietnam_moi/website_sisvietnam.vn/sisvietnamvn/src/main/resources/config/liquibase/)
|
||||
|
||||
## Getting started
|
||||
|
||||
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
|
||||
@@ -97,3 +119,11 @@ cd ..\sisvietnamvn\
|
||||
.\gradlew bootRun
|
||||
|
||||
dùng JHipster
|
||||
|
||||
Lỗi "build failed" vừa rồi khả năng cao là do bộ kiểm tra định dạng code khắt khe spotless của dự án báo lỗi vì tôi đã thay đổi file Java (SecurityConfiguration.java và HomeController.java) mà chưa chuẩn hoá lại khoảng trắng/thụt lề theo đúng chuẩn của hệ thống.
|
||||
|
||||
Tôi đã chạy lệnh ./gradlew spotlessApply để tự động dọn dẹp và sửa lại toàn bộ lỗi định dạng này. Hiện tại lệnh ./gradlew classes và ứng dụng đã hoạt động bình thường, URL /lien-he trả về mã 200 thành công.
|
||||
|
||||
(Lưu ý: Có một lỗi riêng trong lệnh chạy test ./gradlew test liên quan đến cấu hình taskExecutor bị thiếu của dự án gốc đối với môi trường test, nhưng nó hoàn toàn không ảnh hưởng đến việc chạy ứng dụng thực tế bằng ./gradlew bootRun).
|
||||
|
||||
Bạn có thể refresh lại trang web để kiểm tra màu sắc trên menu header nhé, nó đã được sửa lại thành màu đen rồi!
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,900 @@
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWtE6F15M.woff2) format('woff2');
|
||||
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWvU6F15M.woff2) format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWtU6F15M.woff2) format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWuk6F15M.woff2) format('woff2');
|
||||
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
|
||||
}
|
||||
/* hebrew */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWu06F15M.woff2) format('woff2');
|
||||
unicode-range: U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
|
||||
}
|
||||
/* math */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWxU6F15M.woff2) format('woff2');
|
||||
unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;
|
||||
}
|
||||
/* symbols */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqW106F15M.woff2) format('woff2');
|
||||
unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWtk6F15M.woff2) format('woff2');
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWt06F15M.woff2) format('woff2');
|
||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWuU6F.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWtE6F15M.woff2) format('woff2');
|
||||
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWvU6F15M.woff2) format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWtU6F15M.woff2) format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWuk6F15M.woff2) format('woff2');
|
||||
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
|
||||
}
|
||||
/* hebrew */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWu06F15M.woff2) format('woff2');
|
||||
unicode-range: U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
|
||||
}
|
||||
/* math */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWxU6F15M.woff2) format('woff2');
|
||||
unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;
|
||||
}
|
||||
/* symbols */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqW106F15M.woff2) format('woff2');
|
||||
unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWtk6F15M.woff2) format('woff2');
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWt06F15M.woff2) format('woff2');
|
||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWuU6F.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWtE6F15M.woff2) format('woff2');
|
||||
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWvU6F15M.woff2) format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWtU6F15M.woff2) format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWuk6F15M.woff2) format('woff2');
|
||||
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
|
||||
}
|
||||
/* hebrew */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWu06F15M.woff2) format('woff2');
|
||||
unicode-range: U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
|
||||
}
|
||||
/* math */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWxU6F15M.woff2) format('woff2');
|
||||
unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;
|
||||
}
|
||||
/* symbols */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqW106F15M.woff2) format('woff2');
|
||||
unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWtk6F15M.woff2) format('woff2');
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWt06F15M.woff2) format('woff2');
|
||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWuU6F.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWtE6F15M.woff2) format('woff2');
|
||||
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWvU6F15M.woff2) format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWtU6F15M.woff2) format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWuk6F15M.woff2) format('woff2');
|
||||
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
|
||||
}
|
||||
/* hebrew */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWu06F15M.woff2) format('woff2');
|
||||
unicode-range: U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
|
||||
}
|
||||
/* math */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWxU6F15M.woff2) format('woff2');
|
||||
unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;
|
||||
}
|
||||
/* symbols */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqW106F15M.woff2) format('woff2');
|
||||
unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWtk6F15M.woff2) format('woff2');
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWt06F15M.woff2) format('woff2');
|
||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWuU6F.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSKmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSumu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSOmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSymu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
|
||||
}
|
||||
/* hebrew */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS2mu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
|
||||
}
|
||||
/* math */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTVOmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;
|
||||
}
|
||||
/* symbols */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTUGmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSCmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSGmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS-muw.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSKmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSumu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSOmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSymu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
|
||||
}
|
||||
/* hebrew */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS2mu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
|
||||
}
|
||||
/* math */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTVOmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;
|
||||
}
|
||||
/* symbols */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTUGmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSCmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSGmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS-muw.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSKmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSumu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSOmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSymu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
|
||||
}
|
||||
/* hebrew */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS2mu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
|
||||
}
|
||||
/* math */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTVOmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;
|
||||
}
|
||||
/* symbols */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTUGmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSCmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSGmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS-muw.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSKmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSumu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSOmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSymu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
|
||||
}
|
||||
/* hebrew */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS2mu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
|
||||
}
|
||||
/* math */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTVOmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;
|
||||
}
|
||||
/* symbols */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTUGmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSCmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSGmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS-muw.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSKmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSumu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSOmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSymu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
|
||||
}
|
||||
/* hebrew */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS2mu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
|
||||
}
|
||||
/* math */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTVOmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;
|
||||
}
|
||||
/* symbols */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTUGmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSCmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSGmu1aB.woff2) format('woff2');
|
||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS-muw.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
+16
File diff suppressed because one or more lines are too long
+5
@@ -0,0 +1,5 @@
|
||||
/* @license GPL-2.0-or-later https://www.drupal.org/licensing/faq */
|
||||
.c--card-grid [data-component-id="umass_base:description"].f--description a.field-stat-link{display:inline-flex;justify-content:center;align-items:center;position:relative;width:auto;min-width:10.625rem;height:3.125rem;padding:0 0.9375rem;font-family:'Open Sans',Arial,Helvetica,sans-serif;font-size:0.875rem;font-weight:800;line-height:1.2858;text-align:center;text-decoration:none;text-transform:uppercase;white-space:normal;appearance:none;border:0;border-radius:0;color:#fff;background-color:#881c1c;transition:background-color 0.1s ease-in-out;}.c--card-grid [data-component-id="umass_base:description"].f--description a.field-stat-link:hover{background-color:var(--color-brand-dark);color:var(--color-white);}
|
||||
.is-chrome .fi--form-item input[type="date"]::after{top:1rem;}
|
||||
.block-microsite-menu-block svg.ext,.block-microsite-menu-block svg.mailto,.block-microsite-menu-block svg.tel{fill:#ffffff;}.block-microsite-menu-block svg.ext path,.block-microsite-menu-block svg.mailto path,.block-microsite-menu-block svg.tel path{stroke:#ffffff;}
|
||||
.page-node-type-story .publication-date,.story-listing .publication-date{display:none;}.story-listing .f--field.f--eyebrow{display:none;}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
/* @license GPL-2.0-or-later https://www.drupal.org/licensing/faq */
|
||||
.progress{position:relative;}.progress__track{min-width:100px;max-width:100%;height:16px;margin-top:5px;border:1px solid;background-color:#fff;}.progress__bar{width:3%;min-width:3%;max-width:100%;height:1.5em;background-color:#000;}.progress__description,.progress__percentage{overflow:hidden;margin-top:0.2em;color:#555;font-size:0.875em;}.progress__description{float:left;}[dir="rtl"] .progress__description{float:right;}.progress__percentage{float:right;}[dir="rtl"] .progress__percentage{float:left;}.progress--small .progress__track{height:7px;}.progress--small .progress__bar{height:7px;background-size:20px 20px;}
|
||||
.ajax-progress{display:inline-block;padding:1px 5px 2px 5px;}[dir="rtl"] .ajax-progress{float:right;}.ajax-progress-throbber .throbber{display:inline;padding:1px 5px 2px;background:transparent url(/themes/contrib/stable/images/core/throbber-active.gif) no-repeat 0 center;}.ajax-progress-throbber .message{display:inline;padding:1px 5px 2px;}tr .ajax-progress-throbber .throbber{margin:0 2px;}.ajax-progress-bar{width:16em;}.ajax-progress-fullscreen{position:fixed;z-index:1000;top:48.5%;left:49%;width:24px;height:24px;padding:4px;opacity:0.9;border-radius:7px;background-color:#232323;background-image:url(/themes/contrib/stable/images/core/loading-small.gif);background-repeat:no-repeat;background-position:center center;}[dir="rtl"] .ajax-progress-fullscreen{right:49%;left:auto;}
|
||||
.text-align-left{text-align:left;}.text-align-right{text-align:right;}.text-align-center{text-align:center;}.text-align-justify{text-align:justify;}.align-left{float:left;}.align-right{float:right;}.align-center{display:block;margin-right:auto;margin-left:auto;}
|
||||
.container-inline div,.container-inline label{display:inline;}.container-inline .details-wrapper{display:block;}
|
||||
.clearfix:after{display:table;clear:both;content:"";}
|
||||
.hidden{display:none;}.visually-hidden{position:absolute !important;overflow:hidden;clip:rect(1px,1px,1px,1px);width:1px;height:1px;word-wrap:normal;}.visually-hidden.focusable:active,.visually-hidden.focusable:focus{position:static !important;overflow:visible;clip:auto;width:auto;height:auto;}.invisible{visibility:hidden;}
|
||||
.js .js-hide{display:none;}.js-show{display:none;}.js .js-show{display:block;}
|
||||
.cc_banner-wrapper{z-index:9001;position:relative}.cc_container .cc_btn{cursor:pointer;text-align:center;font-size:0.6em;transition:font-size 200ms;line-height:1em}.cc_container .cc_message{font-size:0.6em;transition:font-size 200ms;margin:0;padding:0;line-height:1.5em}.cc_container .cc_logo{display:none;text-indent:-1000px;overflow:hidden;width:100px;height:22px;background-size:cover;background-image:url(//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/1.0.10/logo.png);opacity:0.9;transition:opacity 200ms}.cc_container .cc_logo:hover,.cc_container .cc_logo:active{opacity:1}@media screen and (min-width:500px){.cc_container .cc_btn{font-size:0.8em}.cc_container .cc_message{font-size:0.8em}}@media screen and (min-width:768px){.cc_container .cc_btn{font-size:1em}.cc_container .cc_message{font-size:1em;line-height:1em}}@media screen and (min-width:992px){.cc_container .cc_message{font-size:1em}}@media print{.cc_banner-wrapper,.cc_container{display:none}}.cc_container{position:fixed;left:0;right:0;bottom:0;overflow:hidden;padding:10px}.cc_container .cc_btn{padding:8px 10px;background-color:#f1d600;cursor:pointer;transition:font-size 200ms;text-align:center;font-size:0.6em;display:block;width:33%;margin-left:10px;float:right;max-width:120px}.cc_container .cc_message{transition:font-size 200ms;font-size:0.6em;display:block}@media screen and (min-width:500px){.cc_container .cc_btn{font-size:0.8em}.cc_container .cc_message{margin-top:0.5em;font-size:0.8em}}@media screen and (min-width:768px){.cc_container{padding:15px 30px 15px}.cc_container .cc_btn{font-size:1em;padding:8px 15px}.cc_container .cc_message{font-size:1em}}@media screen and (min-width:992px){.cc_container .cc_message{font-size:1em}}.cc_container{background:#222;color:#fff;font-size:17px;font-family:"Helvetica Neue Light","HelveticaNeue-Light","Helvetica Neue",Calibri,Helvetica,Arial;box-sizing:border-box}.cc_container ::-moz-selection{background:#ff5e99;color:#fff;text-shadow:none}.cc_container .cc_btn,.cc_container .cc_btn:visited{color:#000;background-color:#f1d600;transition:background 200ms ease-in-out,color 200ms ease-in-out,box-shadow 200ms ease-in-out;-webkit-transition:background 200ms ease-in-out,color 200ms ease-in-out,box-shadow 200ms ease-in-out;border-radius:5px;-webkit-border-radius:5px}.cc_container .cc_btn:hover,.cc_container .cc_btn:active{background-color:#fff;color:#000}.cc_container a,.cc_container a:visited{text-decoration:none;color:#31a8f0;transition:200ms color}.cc_container a:hover,.cc_container a:active{color:#b2f7ff}@-webkit-keyframes slideUp{0%{-webkit-transform:translateY(66px);transform:translateY(66px)}100%{-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes slideUp{0%{-webkit-transform:translateY(66px);-ms-transform:translateY(66px);transform:translateY(66px)}100%{-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}}.cc_container,.cc_message,.cc_btn{animation-duration:0.8s;-webkit-animation-duration:0.8s;-moz-animation-duration:0.8s;-o-animation-duration:0.8s;-webkit-animation-name:slideUp;animation-name:slideUp}
|
||||
span.ext{width:10px;height:10px;padding-right:12px;text-decoration:none;background:url(/modules/contrib/extlink/images/extlink_s.png) 2px center no-repeat;}span.mailto{width:10px;height:10px;padding-right:12px;text-decoration:none;background:url(/modules/contrib/extlink/images/extlink_s.png) -20px center no-repeat;}span.tel{width:10px;height:10px;padding-right:12px;text-decoration:none;background:url(/modules/contrib/extlink/images/extlink_s.png) -42px center no-repeat;}svg.ext{width:14px;height:14px;fill:#727272;font-weight:900;}svg.mailto,svg.tel{width:14px;height:14px;fill:#727272;}[data-extlink-placement='prepend'],[data-extlink-placement='before']{padding-right:0.2rem;}[data-extlink-placement='append'],[data-extlink-placement='after']{padding-left:0.2rem;}svg.ext path,svg.mailto path,svg.tel path{stroke:#727272;stroke-width:3;}@media print{svg.ext,svg.mailto,svg.tel,span.ext,span.mailto,span.tel{display:none;padding:0;}}.extlink i{padding-left:0.2em;}.extlink-nobreak{white-space:nowrap;}
|
||||
.paragraph--unpublished{background-color:#fff4f4;}
|
||||
@@ -0,0 +1,43 @@
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag() {
|
||||
dataLayer.push(arguments);
|
||||
}
|
||||
gtag('js', new Date());
|
||||
// Drupal's global gtag ID. For more info: https://developers.google.com/tag-platform/devguides/gtag-integration
|
||||
gtag('set', 'developer_id.dMDhkMT', true);
|
||||
|
||||
(function (drupalSettings) {
|
||||
if (!drupalSettings.gtag) {return;}
|
||||
const config = drupalSettings.gtag;
|
||||
|
||||
if (config.consentMode === true) {
|
||||
gtag('consent', 'default', {
|
||||
ad_storage: 'denied',
|
||||
analytics_storage: 'denied',
|
||||
ad_user_data: 'denied',
|
||||
ad_personalization: 'denied',
|
||||
wait_for_update: 500,
|
||||
});
|
||||
}
|
||||
|
||||
if (config.tagId.length !== 0) {
|
||||
const script = document.createElement('script');
|
||||
script.async = true;
|
||||
script.src = `https://www.googletagmanager.com/gtag/js?id=${config.tagId}`;
|
||||
script.type = 'text/javascript';
|
||||
document.getElementsByTagName('head')[0].appendChild(script);
|
||||
}
|
||||
|
||||
const additionalConfigInfo = config.additionalConfigInfo || [];
|
||||
if (additionalConfigInfo.length === 0) {
|
||||
gtag('config', config.tagId);
|
||||
} else {
|
||||
gtag('config', config.tagId, additionalConfigInfo);
|
||||
}
|
||||
|
||||
const otherIds = config.otherIds || [];
|
||||
otherIds.forEach((id) => gtag('config', id));
|
||||
|
||||
const events = config.events || [];
|
||||
events.forEach((event) => gtag('event', event.name, event.data));
|
||||
})(drupalSettings);
|
||||
@@ -0,0 +1,31 @@
|
||||
const dl = drupalSettings.gtm ? drupalSettings.gtm.settings.data_layer : 'dataLayer';
|
||||
window[dl] = window[dl] || [];
|
||||
|
||||
(function (drupalSettings) {
|
||||
if (!drupalSettings.gtm) {return;}
|
||||
const config = drupalSettings.gtm;
|
||||
|
||||
window[dl].push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' });
|
||||
const gtmSettings = config.settings;
|
||||
if (gtmSettings.include_classes === true) {
|
||||
window[dl].push({
|
||||
'gtm.allowlist': gtmSettings.allowlist_classes ?? [],
|
||||
'gtm.blocklist': gtmSettings.blocklist_classes ?? [],
|
||||
});
|
||||
}
|
||||
|
||||
let gtm_environment = '';
|
||||
if (gtmSettings.include_environment === true) {
|
||||
const gtm_auth = gtmSettings.environment_token ?? '';
|
||||
const gtm_preview = gtmSettings.environment_id ?? '';
|
||||
gtm_environment = `>m_auth=${gtm_auth}>m_preview=${gtm_preview}>m_cookies_win=x`;
|
||||
}
|
||||
config.tagIds.forEach(function (tagId) {
|
||||
const script = document.createElement('script');
|
||||
script.async = true;
|
||||
const dLink = dl != 'dataLayer' ? `&l=${dl}` : '';
|
||||
script.src = `https://www.googletagmanager.com/gtm.js?id=${tagId}${gtm_environment}${dLink}`;
|
||||
script.type = 'text/javascript';
|
||||
document.getElementsByTagName('head')[0].appendChild(script);
|
||||
});
|
||||
})(drupalSettings);
|
||||
File diff suppressed because one or more lines are too long
+63
File diff suppressed because one or more lines are too long
+2
@@ -0,0 +1,2 @@
|
||||
/* @license GPL-2.0-or-later https://www.drupal.org/licensing/faq */
|
||||
(function(){const settingsElement=document.querySelector('head > script[type="application/json"][data-drupal-selector="drupal-settings-json"], body > script[type="application/json"][data-drupal-selector="drupal-settings-json"]');window.drupalSettings={};if(settingsElement!==null)window.drupalSettings=JSON.parse(settingsElement.textContent);})();;
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/* @license GPL-2.0-or-later https://www.drupal.org/licensing/faq */
|
||||
(function(Drupal,$,once){'use strict';var initHoverIntent=function(){var menu=this;$('ul.m--main > li',menu).hoverIntent({over:function(){$(this).addClass('hover');},out:function(){$(this).removeClass('hover');},interval:80});};var initMainMenu=function(){var $menuItems=$('.cc--menu-main ul.m--menu > li');ally.style.focusWithin();$menuItems.on('click',function(){$menuItems.removeClass('ally-focus-within');if(whatInput.ask()==='touch')$(this).addClass('ally-focus-within');});};window.DP.behaviors.mainMenu={attach:function(context){$(once('mainMenu','.nav-container .cc--menu-main',context)).each(function(){initHoverIntent.apply(this);initMainMenu.apply();});}};})(Drupal,jQuery,once);;
|
||||
(function(Drupal,$,once){'use strict';var $hamburger;var $mobileMenu;var $arrowToggles;var $backButtons;var $subMenus;var breakpoint=window.matchMedia('(min-width: 1200px)');var initMobileMenu=function(){$hamburger=$(this);$mobileMenu=$('.cc--menu-mobile');$arrowToggles=$mobileMenu.find('.arrow-toggle');$subMenus=$mobileMenu.find('.submenu-wrapper');$backButtons=$mobileMenu.find('.button-back');$hamburger.on('click',function(e){e.preventDefault();toggleMobileMenu(this);});$arrowToggles.on('click',function(e){e.preventDefault();var $subMenu=$(this).parents('.menu-item').find('.submenu-wrapper');$subMenu.attr('aria-hidden','false');$subMenu.show();$subMenu.removeClass('is-hidden').addClass('is-visible');$mobileMenu.addClass('is-hidden');});$backButtons.on('click',function(e){e.preventDefault();var $this=$(this);$this.parents('.submenu-wrapper').attr('aria-hidden','true');$this.parents('.submenu-wrapper').addClass('is-hidden');$this.parents('.submenu-wrapper').removeClass('is-visible');$mobileMenu.removeClass('is-hidden');});checkBreakpoint();breakpoint.addListener(checkBreakpoint);};var checkBreakpoint=function(){if(breakpoint.matches){$hamburger.removeClass('is-active');$mobileMenu.removeAttr('style');$('body').removeClass('mobile-menu-is-active');hideAllSubmenus();}};var toggleMobileMenu=function(el){$('body').toggleClass('mobile-menu-is-active');$(el).toggleClass('is-active');$mobileMenu.fadeToggle(function(){if(!$('body').hasClass('mobile-menu-is-active'))hideAllSubmenus();});};var hideAllSubmenus=function(){$subMenus.removeClass('is-visible');$mobileMenu.removeClass('is-hidden');};window.DP.behaviors.mobileMenu={attach:function(context){$(once('mobileMenu','.hamburger',context)).each(function(){initMobileMenu.apply(this);});}};}(Drupal,jQuery,once));;
|
||||
(function($){'use strict';var $searchIcon;var $body=$('body');var $searchFormContainer=$('.cc--header .cc--header-search');var $searchInput=$searchFormContainer.find('input');var $closeIcon=$searchFormContainer.find('.button-close');var initSearchForm=function(){$searchIcon=$(this);$searchFormContainer.attr({'aria-hidden':'true'});$searchIcon.on('click',function(e){e.preventDefault();openSearch();});$closeIcon.on('click',function(e){e.preventDefault();closeSearch();});$searchFormContainer.on('keydown',function(ev){if(ev.keyCode===9){var inputs=$searchFormContainer.find('input, button').filter(':visible').not(':disabled');if(!ev.shiftKey){if(inputs[inputs.length-1]===ev.target){ev.preventDefault();inputs.first().focus();}}else{if(inputs[0]===ev.target){ev.preventDefault();inputs.last().focus();}}}if(ev.keyCode===27){ev.preventDefault();closeSearch();}});};var openSearch=function(){$searchFormContainer.addClass('is-open').attr('aria-hidden','false');$body.addClass('search-open');$searchInput.first().focus();};var closeSearch=function(){$searchFormContainer.removeClass('is-open').attr('aria-hidden','true');$body.removeClass('search-open');};window.DP.behaviors.searchForm={attach:function(context){$(once('searchForm','.utility-nav-container .search-button',context)).each(function(){initSearchForm.apply(this);});}};}(jQuery));;
|
||||
/**
|
||||
* what-input - A global utility for tracking the current input method (mouse, keyboard or touch).
|
||||
* @version v5.2.3
|
||||
* @link https://github.com/ten1seven/what-input
|
||||
* @license MIT
|
||||
*/
|
||||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("whatInput",[],t):"object"==typeof exports?exports.whatInput=t():e.whatInput=t()}(this,function(){return i={},n.m=o=[function(e,t){"use strict";e.exports=function(){if("undefined"==typeof document||"undefined"==typeof window)return{ask:function(){return"initial"},element:function(){return null},ignoreKeys:function(){},specificKeys:function(){},registerOnChange:function(){},unRegisterOnChange:function(){}};var t=document.documentElement,n=null,a="initial",u=a,o=Date.now();try{window.sessionStorage.getItem("what-input")&&(a=window.sessionStorage.getItem("what-input")),window.sessionStorage.getItem("what-intent")&&(u=window.sessionStorage.getItem("what-intent"))}catch(e){}var d=["button","input","select","textarea"],i=[],c=[16,17,18,91,93],w=[],p={keydown:"keyboard",keyup:"keyboard",mousedown:"mouse",mousemove:"mouse",MSPointerDown:"pointer",MSPointerMove:"pointer",pointerdown:"pointer",pointermove:"pointer",touchstart:"touch",touchend:"touch"},r=!1,s={x:null,y:null},f={2:"touch",3:"touch",4:"mouse"},l=!1;try{var e=Object.defineProperty({},"passive",{get:function(){l=!0}});window.addEventListener("test",null,e)}catch(e){}var h=function(){var e=!!l&&{passive:!0};window.PointerEvent?(window.addEventListener("pointerdown",m),window.addEventListener("pointermove",y)):window.MSPointerEvent?(window.addEventListener("MSPointerDown",m),window.addEventListener("MSPointerMove",y)):(window.addEventListener("mousedown",m),window.addEventListener("mousemove",y),"ontouchstart"in window&&(window.addEventListener("touchstart",m,e),window.addEventListener("touchend",m))),window.addEventListener(S(),y,e),window.addEventListener("keydown",m),window.addEventListener("keyup",m),window.addEventListener("focusin",g),window.addEventListener("focusout",E)},m=function(e){var t=e.which,n=p[e.type];"pointer"===n&&(n=L(e));var o=!w.length&&-1===c.indexOf(t),i=w.length&&-1!==w.indexOf(t),r="keyboard"===n&&t&&(o||i)||"mouse"===n||"touch"===n;if(x(n)&&(r=!1),r&&a!==n){a=n;try{window.sessionStorage.setItem("what-input",a)}catch(e){}v("input")}if(r&&u!==n){var s=document.activeElement;if(s&&s.nodeName&&(-1===d.indexOf(s.nodeName.toLowerCase())||"button"===s.nodeName.toLowerCase()&&!O(s,"form"))){u=n;try{window.sessionStorage.setItem("what-intent",u)}catch(e){}v("intent")}}},v=function(e){t.setAttribute("data-what"+e,"input"===e?a:u),b(e)},y=function(e){var t=p[e.type];if("pointer"===t&&(t=L(e)),M(e),(!r&&!x(t)||r&&"wheel"===e.type||"mousewheel"===e.type||"DOMMouseScroll"===e.type)&&u!==t){u=t;try{window.sessionStorage.setItem("what-intent",u)}catch(e){}v("intent")}},g=function(e){e.target.nodeName?(n=e.target.nodeName.toLowerCase(),t.setAttribute("data-whatelement",n),e.target.classList&&e.target.classList.length&&t.setAttribute("data-whatclasses",e.target.classList.toString().replace(" ",","))):E()},E=function(){n=null,t.removeAttribute("data-whatelement"),t.removeAttribute("data-whatclasses")},L=function(e){return"number"==typeof e.pointerType?f[e.pointerType]:"pen"===e.pointerType?"touch":e.pointerType},x=function(e){var t=Date.now(),n="mouse"===e&&"touch"===a&&t-o<200;return o=t,n},S=function(){return"onwheel"in document.createElement("div")?"wheel":void 0!==document.onmousewheel?"mousewheel":"DOMMouseScroll"},b=function(e){for(var t=0,n=i.length;t<n;t++)i[t].type===e&&i[t].fn.call(void 0,"input"===e?a:u)},M=function(e){s.x!==e.screenX||s.y!==e.screenY?(r=!1,s.x=e.screenX,s.y=e.screenY):r=!0},O=function(e,t){var n=window.Element.prototype;if(n.matches||(n.matches=n.msMatchesSelector||n.webkitMatchesSelector),n.closest)return e.closest(t);do{if(e.matches(t))return e;e=e.parentElement||e.parentNode}while(null!==e&&1===e.nodeType);return null};return"addEventListener"in window&&Array.prototype.indexOf&&(p[S()]="mouse",h(),v("input"),v("intent")),{ask:function(e){return"intent"===e?u:a},element:function(){return n},ignoreKeys:function(e){c=e},specificKeys:function(e){w=e},registerOnChange:function(e,t){i.push({fn:e,type:t||"input"})},unRegisterOnChange:function(e){var t=function(e){for(var t=0,n=i.length;t<n;t++)if(i[t].fn===e)return t}(e);!t&&0!==t||i.splice(t,1)}}}()}],n.c=i,n.p="",n(0);function n(e){if(i[e])return i[e].exports;var t=i[e]={exports:{},id:e,loaded:!1};return o[e].call(t.exports,t,t.exports,n),t.loaded=!0,t.exports}var o,i});
|
||||
|
||||
;
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.209.6/containers/java/.devcontainer/base.Dockerfile
|
||||
|
||||
# [Choice] Java version (use -bullseye variants on local arm64/Apple Silicon): 17, 17-bullseye, 17-buster
|
||||
ARG VARIANT="17"
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/java:0-${VARIANT}
|
||||
|
||||
# [Option] Install Maven
|
||||
ARG INSTALL_MAVEN="false"
|
||||
ARG MAVEN_VERSION=""
|
||||
# [Option] Install Gradle
|
||||
ARG INSTALL_GRADLE="false"
|
||||
ARG GRADLE_VERSION=""
|
||||
RUN if [ "${INSTALL_MAVEN}" = "true" ]; then su vscode -c "umask 0002 && . /usr/local/sdkman/bin/sdkman-init.sh && sdk install maven \"${MAVEN_VERSION}\""; fi \
|
||||
&& if [ "${INSTALL_GRADLE}" = "true" ]; then su vscode -c "umask 0002 && . /usr/local/sdkman/bin/sdkman-init.sh && sdk install gradle \"${GRADLE_VERSION}\""; fi
|
||||
|
||||
# [Choice] Node.js version: none, lts/*, 16, 14, 12, 10
|
||||
ARG NODE_VERSION="none"
|
||||
RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
|
||||
|
||||
# [Optional] Uncomment this section to install additional OS packages.
|
||||
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||
# && apt-get -y install --no-install-recommends <your-package-list-here>
|
||||
|
||||
# [Optional] Uncomment this line to install global node packages.
|
||||
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1
|
||||
@@ -0,0 +1,49 @@
|
||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
|
||||
// https://github.com/microsoft/vscode-dev-containers/tree/v0.209.6/containers/java
|
||||
{
|
||||
"name": "Sisvietnamvn",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
"args": {
|
||||
// Update the VARIANT arg to pick a Java version: 17, 19
|
||||
// Append -bullseye or -buster to pin to an OS version.
|
||||
// Use the -bullseye variants on local arm64/Apple Silicon.
|
||||
"VARIANT": "21-bullseye",
|
||||
// Options
|
||||
// maven and gradle wrappers are used by default, we don't need them installed globally
|
||||
// "INSTALL_MAVEN": "false",
|
||||
// "INSTALL_GRADLE": "true",
|
||||
"NODE_VERSION": "24.16.0"
|
||||
}
|
||||
},
|
||||
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
// Set *default* container specific settings.json values on container create.
|
||||
"settings": {
|
||||
"java.jdt.ls.java.home": "/docker-java-home"
|
||||
},
|
||||
|
||||
// Add the IDs of extensions you want installed when the container is created.
|
||||
"extensions": ["vscjava.vscode-java-pack", "pivotal.vscode-boot-dev-pack", "esbenp.prettier-vscode"]
|
||||
}
|
||||
},
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
"forwardPorts": [8080],
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
// "postCreateCommand": "java -version",
|
||||
|
||||
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
||||
"remoteUser": "vscode",
|
||||
|
||||
// Mount the workspace folder to the same path inside the container, so docker-in-docker containers work correctly. See https://github.com/jhipster/generator-jhipster/issues/31239
|
||||
"workspaceMount": "source=${localWorkspaceFolder},target=${localWorkspaceFolder},type=bind",
|
||||
"workspaceFolder": "${localWorkspaceFolder}",
|
||||
|
||||
"features": {
|
||||
"docker-in-docker": "latest",
|
||||
"docker-from-docker": "latest"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
# EditorConfig helps developers define and maintain consistent
|
||||
# coding styles between different editors and IDEs
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
|
||||
# We recommend you to keep these unchanged
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
# Change these settings to your own preference
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
# Generated by jhipster:java:bootstrap generator
|
||||
[*.java]
|
||||
indent_size = 4
|
||||
+149
-3
@@ -1,3 +1,149 @@
|
||||
/gradlew text eol=lf
|
||||
*.bat text eol=crlf
|
||||
*.jar binary
|
||||
# This file is inspired by https://github.com/alexkaratarakis/gitattributes
|
||||
#
|
||||
# Auto detect text files and perform LF normalization
|
||||
# https://davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/
|
||||
* text=auto
|
||||
|
||||
# The above will handle all files NOT found below
|
||||
# These files are text and should be normalized (Convert crlf => lf)
|
||||
|
||||
*.bat text eol=crlf
|
||||
*.cmd text eol=crlf
|
||||
*.ps1 text eol=crlf
|
||||
*.coffee text
|
||||
*.css text
|
||||
*.cql text
|
||||
*.df text
|
||||
*.ejs text
|
||||
*.html text
|
||||
*.java text
|
||||
*.js text
|
||||
*.json text
|
||||
*.less text
|
||||
*.properties text
|
||||
*.sass text
|
||||
*.scss text
|
||||
*.sh text eol=lf
|
||||
*.sql text
|
||||
*.ts text
|
||||
*.xml text
|
||||
*.yaml text
|
||||
*.yml text
|
||||
|
||||
# Documents
|
||||
*.doc diff=astextplain
|
||||
*.DOC diff=astextplain
|
||||
*.docx diff=astextplain
|
||||
*.DOCX diff=astextplain
|
||||
*.dot diff=astextplain
|
||||
*.DOT diff=astextplain
|
||||
*.pdf diff=astextplain
|
||||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
||||
*.markdown text
|
||||
*.md text
|
||||
*.adoc text
|
||||
*.textile text
|
||||
*.mustache text
|
||||
*.csv text
|
||||
*.tab text
|
||||
*.tsv text
|
||||
*.txt text
|
||||
AUTHORS text
|
||||
CHANGELOG text
|
||||
CHANGES text
|
||||
CONTRIBUTING text
|
||||
COPYING text
|
||||
copyright text
|
||||
*COPYRIGHT* text
|
||||
INSTALL text
|
||||
license text
|
||||
LICENSE text
|
||||
NEWS text
|
||||
readme text
|
||||
*README* text
|
||||
TODO text
|
||||
|
||||
# Graphics
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.gif binary
|
||||
*.tif binary
|
||||
*.tiff binary
|
||||
*.ico binary
|
||||
# SVG treated as an asset (binary) by default. If you want to treat it as text,
|
||||
# comment-out the following line and uncomment the line after.
|
||||
*.svg binary
|
||||
#*.svg text
|
||||
*.eps binary
|
||||
|
||||
# These files are binary and should be left untouched
|
||||
# (binary is a macro for -text -diff)
|
||||
*.class binary
|
||||
*.jar binary
|
||||
*.war binary
|
||||
|
||||
## LINTERS
|
||||
.csslintrc text
|
||||
.eslintrc text
|
||||
.jscsrc text
|
||||
.jshintrc text
|
||||
.jshintignore text
|
||||
.stylelintrc text
|
||||
|
||||
## CONFIGS
|
||||
*.conf text
|
||||
*.config text
|
||||
.editorconfig text
|
||||
.gitattributes text
|
||||
.gitconfig text
|
||||
.gitignore text
|
||||
.htaccess text
|
||||
*.npmignore text
|
||||
|
||||
## HEROKU
|
||||
Procfile text
|
||||
.slugignore text
|
||||
|
||||
## AUDIO
|
||||
*.kar binary
|
||||
*.m4a binary
|
||||
*.mid binary
|
||||
*.midi binary
|
||||
*.mp3 binary
|
||||
*.ogg binary
|
||||
*.ra binary
|
||||
|
||||
## VIDEO
|
||||
*.3gpp binary
|
||||
*.3gp binary
|
||||
*.as binary
|
||||
*.asf binary
|
||||
*.asx binary
|
||||
*.fla binary
|
||||
*.flv binary
|
||||
*.m4v binary
|
||||
*.mng binary
|
||||
*.mov binary
|
||||
*.mp4 binary
|
||||
*.mpeg binary
|
||||
*.mpg binary
|
||||
*.swc binary
|
||||
*.swf binary
|
||||
*.webm binary
|
||||
|
||||
## ARCHIVES
|
||||
*.7z binary
|
||||
*.gz binary
|
||||
*.rar binary
|
||||
*.tar binary
|
||||
*.zip binary
|
||||
|
||||
## FONTS
|
||||
*.ttf binary
|
||||
*.eot binary
|
||||
*.otf binary
|
||||
*.woff binary
|
||||
*.woff2 binary
|
||||
|
||||
+151
-35
@@ -1,37 +1,153 @@
|
||||
HELP.md
|
||||
.gradle
|
||||
build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
bin/
|
||||
!**/src/main/**/bin/
|
||||
!**/src/test/**/bin/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
out/
|
||||
!**/src/main/**/out/
|
||||
!**/src/test/**/out/
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
######################
|
||||
# Node
|
||||
######################
|
||||
/node/
|
||||
node_tmp/
|
||||
node_modules/
|
||||
npm-debug.log.*
|
||||
/.awcache/*
|
||||
/.cache-loader/*
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
######################
|
||||
# SASS
|
||||
######################
|
||||
.sass-cache/
|
||||
|
||||
######################
|
||||
# Eclipse
|
||||
######################
|
||||
*.pydevproject
|
||||
.project
|
||||
.metadata
|
||||
tmp/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
local.properties
|
||||
.classpath
|
||||
.settings/
|
||||
.loadpath
|
||||
.factorypath
|
||||
|
||||
# External tool builders
|
||||
.externalToolBuilders/**
|
||||
|
||||
# Locally stored "Eclipse launch configurations"
|
||||
*.launch
|
||||
|
||||
# CDT-specific
|
||||
.cproject
|
||||
|
||||
# PDT-specific
|
||||
.buildpath
|
||||
|
||||
# STS-specific
|
||||
/.sts4-cache/*
|
||||
|
||||
######################
|
||||
# IntelliJ
|
||||
######################
|
||||
.idea/
|
||||
*.iml
|
||||
*.iws
|
||||
*.ipr
|
||||
*.ids
|
||||
*.orig
|
||||
classes/
|
||||
out/
|
||||
|
||||
######################
|
||||
# Visual Studio Code
|
||||
######################
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
*.code-workspace
|
||||
|
||||
######################
|
||||
# Maven
|
||||
######################
|
||||
/log/
|
||||
/target/
|
||||
|
||||
######################
|
||||
# Gradle
|
||||
######################
|
||||
.gradle/
|
||||
/build/
|
||||
/buildSrc/.gradle/
|
||||
/buildSrc/build/
|
||||
|
||||
######################
|
||||
# Package Files
|
||||
######################
|
||||
*.jar
|
||||
*.war
|
||||
*.ear
|
||||
*.db
|
||||
|
||||
######################
|
||||
# Windows
|
||||
######################
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
######################
|
||||
# Mac OSX
|
||||
######################
|
||||
.DS_Store
|
||||
.svn
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear on external disk
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
|
||||
######################
|
||||
# Directories
|
||||
######################
|
||||
/bin/
|
||||
/deploy/
|
||||
|
||||
######################
|
||||
# Logs
|
||||
######################
|
||||
*.log*
|
||||
|
||||
######################
|
||||
# Others
|
||||
######################
|
||||
*.class
|
||||
*.*~
|
||||
*~
|
||||
.merge_file*
|
||||
|
||||
######################
|
||||
# Gradle Wrapper
|
||||
######################
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
######################
|
||||
# Maven Wrapper
|
||||
######################
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
######################
|
||||
# ESLint
|
||||
######################
|
||||
.eslintcache
|
||||
|
||||
######################
|
||||
# Code coverage
|
||||
######################
|
||||
coverage/
|
||||
.nyc_output/
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
node_modules
|
||||
package-lock.json
|
||||
.git
|
||||
|
||||
# Generated by jhipster:java-simple-application:gradle
|
||||
build
|
||||
gradle
|
||||
.gradle
|
||||
@@ -0,0 +1,13 @@
|
||||
printWidth: 140
|
||||
singleQuote: true
|
||||
tabWidth: 2
|
||||
useTabs: false
|
||||
arrowParens: avoid
|
||||
bracketSameLine: false
|
||||
plugins:
|
||||
- prettier-plugin-packagejson
|
||||
- prettier-plugin-java
|
||||
overrides:
|
||||
- files: "*.java"
|
||||
options:
|
||||
tabWidth: 4
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"java.compile.nullAnalysis.mode": "automatic"
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"generator-jhipster": {
|
||||
"applicationType": "monolith",
|
||||
"authenticationType": "jwt",
|
||||
"baseName": "sisvietnamvn",
|
||||
"buildTool": "gradle",
|
||||
"cacheProvider": "ehcache",
|
||||
"clientFramework": "no",
|
||||
"creationTimestamp": 1717387200000,
|
||||
"databaseType": "sql",
|
||||
"defaultCommand": "app",
|
||||
"devDatabaseType": "h2Disk",
|
||||
"enableHibernateCache": true,
|
||||
"enableSwaggerCodegen": false,
|
||||
"enableTranslation": false,
|
||||
"entities": [],
|
||||
"jhiPrefix": "jhi",
|
||||
"jhipsterVersion": "9.1.0",
|
||||
"jwtSecretKey": "ZWRjOTBhYjJiYzg5N2JhMTUyMTBiYzZhNzJjMWUwNmYzOTM3MjJmZGE3Zjc3NGE0ODhjMDZlYzRjNmFiODFhMDNkNmFjNmYwYzY4NmMwNGRkMDMwY2Q0NTllNDlhYzEyMjg0NmY2NzM5MWM1M2IxOTdkMDNhZTBhZDkzYWJjMWI=",
|
||||
"messageBroker": "no",
|
||||
"monorepository": true,
|
||||
"nativeLanguage": "en",
|
||||
"packageFolder": "com/sisvietnamvn/web/",
|
||||
"packageName": "com.sisvietnamvn.web",
|
||||
"prodDatabaseType": "oracle",
|
||||
"searchEngine": "no",
|
||||
"serverPort": 8080,
|
||||
"skipClient": true,
|
||||
"skipCommitHook": true,
|
||||
"skipUserManagement": false,
|
||||
"testFrameworks": []
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
# Getting Started
|
||||
|
||||
### Reference Documentation
|
||||
For further reference, please consider the following sections:
|
||||
|
||||
* [Official Gradle documentation](https://docs.gradle.org)
|
||||
* [Spring Boot Gradle Plugin Reference Guide](https://docs.spring.io/spring-boot/4.0.6/gradle-plugin)
|
||||
* [Create an OCI image](https://docs.spring.io/spring-boot/4.0.6/gradle-plugin/packaging-oci-image.html)
|
||||
* [Spring Web](https://docs.spring.io/spring-boot/4.0.6/reference/web/servlet.html)
|
||||
* [Thymeleaf](https://docs.spring.io/spring-boot/4.0.6/reference/web/servlet.html#web.servlet.spring-mvc.template-engines)
|
||||
* [Spring Boot DevTools](https://docs.spring.io/spring-boot/4.0.6/reference/using/devtools.html)
|
||||
|
||||
### Guides
|
||||
The following guides illustrate how to use some features concretely:
|
||||
|
||||
* [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/)
|
||||
* [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/)
|
||||
* [Building REST services with Spring](https://spring.io/guides/tutorials/rest/)
|
||||
* [Handling Form Submission](https://spring.io/guides/gs/handling-form-submission/)
|
||||
|
||||
### Additional Links
|
||||
These additional references should also help you:
|
||||
|
||||
* [Gradle Build Scans – insights for your project's build](https://scans.gradle.com#gradle)
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
# sisvietnamvn
|
||||
|
||||
This application was generated using JHipster 9.1.0, you can find documentation and help at [https://www.jhipster.tech/documentation-archive/v9.1.0](https://www.jhipster.tech/documentation-archive/v9.1.0).
|
||||
|
||||
## Project Structure
|
||||
|
||||
Node is required for generation and recommended for development. `package.json` is always generated for a better development experience with prettier, commit hooks, scripts and so on.
|
||||
|
||||
In the project root, JHipster generates configuration files for tools like git, prettier, eslint, husky, and others that are well known and you can find references in the web.
|
||||
|
||||
`/src/*` structure follows default Java structure.
|
||||
|
||||
- `.yo-rc.json` - Yeoman configuration file
|
||||
JHipster configuration is stored in this file at `generator-jhipster` key. You may find `generator-jhipster-*` for specific blueprints configuration.
|
||||
- `.yo-resolve` (optional) - Yeoman conflict resolver
|
||||
Allows to use a specific action when conflicts are found skipping prompts for files that matches a pattern. Each line should match `[pattern] [action]` with pattern been a [Minimatch](https://github.com/isaacs/minimatch#minimatch) pattern and action been one of skip (default if omitted) or force. Lines starting with `#` are considered comments and are ignored.
|
||||
- `.jhipster/*.json` - JHipster entity configuration files
|
||||
- `/src/main/docker` - Docker configurations for the application and services that the application depends on
|
||||
|
||||
## Database Configuration
|
||||
|
||||
### Development Database (H2 Console)
|
||||
- **Profile**: `dev`
|
||||
- **Database Type**: H2 (File-based, embedded)
|
||||
- **JDBC URL**: `jdbc:h2:file:./build/h2db/db/sisvietnamvn`
|
||||
- **Username**: `sisvietnamvn`
|
||||
- **Password**: *(leave blank)*
|
||||
- **Console Access**: [http://localhost:8080/h2-console](http://localhost:8080/h2-console) (requires app running in dev profile)
|
||||
- **Config File**: [application-dev.yml](file:///d:/website_sisvietnam_moi/website_sisvietnam.vn/sisvietnamvn/src/main/resources/config/application-dev.yml)
|
||||
|
||||
### Production Database
|
||||
- **Profile**: `prod`
|
||||
- **Database Type**: Oracle Database
|
||||
- **JDBC URL**: `jdbc:oracle:thin:@localhost:1521:xe`
|
||||
- **Username**: `sisvietnamvn`
|
||||
- **Config File**: [application-prod.yml](file:///d:/website_sisvietnam_moi/website_sisvietnam.vn/sisvietnamvn/src/main/resources/config/application-prod.yml)
|
||||
|
||||
### Schema Management
|
||||
- **Tool**: Liquibase
|
||||
- **Changelog Folder**: [src/main/resources/config/liquibase/](file:///d:/website_sisvietnam_moi/website_sisvietnam.vn/sisvietnamvn/src/main/resources/config/liquibase/)
|
||||
|
||||
## Development
|
||||
|
||||
To start your application in the dev profile, run:
|
||||
|
||||
```bash
|
||||
./gradlew
|
||||
```
|
||||
|
||||
For further instructions on how to develop with JHipster, have a look at [Using JHipster in development][].
|
||||
|
||||
## Building for production
|
||||
|
||||
### Packaging as jar
|
||||
|
||||
To build the final jar and optimize the sisvietnamvn application for production, run:
|
||||
|
||||
```bash
|
||||
./gradlew -Pprod clean bootJar
|
||||
```
|
||||
|
||||
To ensure everything worked, run:
|
||||
|
||||
```bash
|
||||
java -jar build/libs/*.jar
|
||||
```
|
||||
|
||||
Refer to [Using JHipster in production][] for more details.
|
||||
|
||||
### Packaging as war
|
||||
|
||||
To package your application as a war in order to deploy it to an application server, run:
|
||||
|
||||
```bash
|
||||
./gradlew -Pprod -Pwar clean bootWar
|
||||
```
|
||||
|
||||
### JHipster Control Center
|
||||
|
||||
JHipster Control Center can help you manage and control your application(s). You can start a local control center server (accessible on http://localhost:7419) with:
|
||||
|
||||
```bash
|
||||
docker compose -f src/main/docker/jhipster-control-center.yml up
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
### Spring Boot tests
|
||||
|
||||
To launch your application's tests, run:
|
||||
|
||||
```bash
|
||||
./gradlew test integrationTest jacocoTestReport
|
||||
```
|
||||
|
||||
## Others
|
||||
|
||||
### Code quality using Sonar
|
||||
|
||||
Sonar is used to analyse code quality. You can start a local Sonar server (accessible on http://localhost:9001) with:
|
||||
|
||||
```bash
|
||||
docker compose -f src/main/docker/sonar.yml up -d
|
||||
```
|
||||
|
||||
Note: we have turned off forced authentication redirect for UI in [src/main/docker/sonar.yml](src/main/docker/sonar.yml) for out of the box experience while trying out SonarQube, for real use cases turn it back on.
|
||||
|
||||
You can run a Sonar analysis with using the [sonar-scanner](https://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner) or by using the gradle plugin.
|
||||
|
||||
Then, run a Sonar analysis:
|
||||
|
||||
```bash
|
||||
./gradlew -Pprod clean check jacocoTestReport sonarqube -Dsonar.login=admin -Dsonar.password=admin
|
||||
```
|
||||
|
||||
Additionally, Instead of passing `sonar.password` and `sonar.login` as CLI arguments, these parameters can be configured from [sonar-project.properties](sonar-project.properties) as shown below:
|
||||
|
||||
```bash
|
||||
sonar.login=admin
|
||||
sonar.password=admin
|
||||
```
|
||||
|
||||
For more information, refer to the [Code quality page][].
|
||||
|
||||
### Docker Compose support
|
||||
|
||||
JHipster generates a number of Docker Compose configuration files in the [src/main/docker/](src/main/docker/) folder to launch required third party services.
|
||||
|
||||
For example, to start required services in Docker containers, run:
|
||||
|
||||
```bash
|
||||
docker compose -f src/main/docker/services.yml up -d
|
||||
```
|
||||
|
||||
To stop and remove the containers, run:
|
||||
|
||||
```bash
|
||||
docker compose -f src/main/docker/services.yml down
|
||||
```
|
||||
|
||||
[Spring Docker Compose Integration](https://docs.spring.io/spring-boot/reference/features/dev-services.html) is enabled by default. It's possible to disable it in `application.yml`:
|
||||
|
||||
```yaml
|
||||
spring:
|
||||
...
|
||||
docker:
|
||||
compose:
|
||||
enabled: false
|
||||
```
|
||||
|
||||
You can also fully dockerize your application and all the services that it depends on.
|
||||
To achieve this, first build a Docker image of your app by running:
|
||||
|
||||
```bash
|
||||
npm run java:docker
|
||||
```
|
||||
|
||||
Or build an arm64 Docker image when using an arm64 processor OS, i.e., Apple Silicon chips (M\*), running:
|
||||
|
||||
```bash
|
||||
npm run java:docker:arm64
|
||||
```
|
||||
|
||||
Then run:
|
||||
|
||||
```bash
|
||||
docker compose -f src/main/docker/app.yml up -d
|
||||
```
|
||||
|
||||
For more information refer to [Docker and Docker-Compose](https://www.jhipster.tech/documentation-archive/v9.1.0/docker-compose/), this page also contains information on the Docker Compose sub-generator (`jhipster docker-compose`), which is able to generate Docker configurations for one or several JHipster applications.
|
||||
|
||||
## Continuous Integration (optional)
|
||||
|
||||
To configure CI for your project, run the ci-cd sub-generator (`jhipster ci-cd`), this will let you generate configuration files for a number of Continuous Integration systems. Consult the [Setting up Continuous Integration](https://www.jhipster.tech/documentation-archive/v9.1.0/setting-up-ci/) page for more information.
|
||||
|
||||
## References
|
||||
|
||||
- [JHipster Homepage and latest documentation](https://www.jhipster.tech/)
|
||||
- [JHipster 9.1.0 archive](https://www.jhipster.tech/documentation-archive/v9.1.0)
|
||||
- [Using JHipster in development](https://www.jhipster.tech/documentation-archive/v9.1.0/development/)
|
||||
- [Using Docker and Docker-Compose](https://www.jhipster.tech/documentation-archive/v9.1.0/docker-compose)
|
||||
- [Using JHipster in production](https://www.jhipster.tech/documentation-archive/v9.1.0/production/)
|
||||
- [Running tests page](https://www.jhipster.tech/documentation-archive/v9.1.0/running-tests/)
|
||||
- [Code quality page](https://www.jhipster.tech/documentation-archive/v9.1.0/code-quality/)
|
||||
- [Setting up Continuous Integration](https://www.jhipster.tech/documentation-archive/v9.1.0/setting-up-ci/)
|
||||
- [Node.js](https://nodejs.org/)
|
||||
- [NPM](https://www.npmjs.com/)
|
||||
|
||||
## Deployment Guide (Ubuntu server + aaPanel + Executable JAR)
|
||||
|
||||
### 1. Build the JAR file (on Windows)
|
||||
Spring Boot applications come with a built-in web server, meaning you can package your entire application into a single executable `.jar` file!
|
||||
Run the following command on your Windows PC to build the production-ready `.jar` file:
|
||||
```powershell
|
||||
./gradlew -Pprod clean bootJar
|
||||
```
|
||||
Alternatively, you can use the built-in npm script:
|
||||
```powershell
|
||||
npm run java:jar:prod
|
||||
```
|
||||
The generated `.jar` file will be located at `build/libs/sisvietnamvn-1.0.3.jar`.
|
||||
|
||||
### 2. Deploy and Run the application (on Ubuntu Server)
|
||||
|
||||
You have two main options to run the application on Ubuntu: using **aaPanel** or using standard **systemd**.
|
||||
|
||||
#### Option A: Using aaPanel (Recommended)
|
||||
If you are using aaPanel, it is highly recommended to use its built-in **Java Project** manager to easily run the JAR file.
|
||||
|
||||
1. **Install Java 21**: Make sure Java 21 is installed on your Ubuntu server via aaPanel.
|
||||
2. **Upload the JAR**: Upload the `sisvietnamvn-1.0.3.jar` file to a folder on your server (e.g., `/www/wwwroot/sisvietnam.vn/`).
|
||||
3. **Add Java Project**: In aaPanel, go to **Website** -> **Java Project** -> **Add Java project**.
|
||||
4. **Configure Project**:
|
||||
- **Project Type**: `Spring_boot`
|
||||
- **Project jar**: Select the `sisvietnamvn-1.0.3.jar` file you just uploaded.
|
||||
- **Project Port**: `8080` (or whichever port your app is configured to use).
|
||||
- **Run user**: `www` (or `root`)
|
||||
- Click **Submit**. aaPanel will automatically run your JAR file in the background!
|
||||
|
||||
#### Option B: Using systemd (Standard Ubuntu)
|
||||
If you prefer managing the server manually via terminal, you can register the JAR as a `systemd` service so it runs continuously in the background and starts automatically on boot.
|
||||
|
||||
1. **Upload the JAR**: Upload the `sisvietnamvn-1.0.3.jar` file to your server (e.g., `/var/www/sisvietnam/sisvietnamvn.jar`).
|
||||
2. **Create the Service File**:
|
||||
```bash
|
||||
sudo nano /etc/systemd/system/sisvietnam.service
|
||||
```
|
||||
3. **Add Configuration**: Paste the following, making sure the `ExecStart` path matches where you put the jar.
|
||||
```ini
|
||||
[Unit]
|
||||
Description=SIS Vietnam Spring Boot Application
|
||||
After=syslog.target network.target
|
||||
|
||||
[Service]
|
||||
User=root
|
||||
ExecStart=/usr/bin/java -jar /var/www/sisvietnam/sisvietnamvn.jar
|
||||
SuccessExitStatus=143
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
4. **Start the Service**: Run the following commands to reload systemd, enable the service to start on boot, and start it now:
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable sisvietnam.service
|
||||
sudo systemctl start sisvietnam.service
|
||||
```
|
||||
5. **Check Status & Logs**:
|
||||
- To check if it's running: `sudo systemctl status sisvietnam.service`
|
||||
- To view the live terminal output: `sudo journalctl -u sisvietnam.service -f`
|
||||
|
||||
### 3. Configure NGINX Reverse Proxy (aaPanel)
|
||||
When you set up a Java Project in aaPanel, it can automatically map your domain and set up a reverse proxy. If you need to verify or set it up manually:
|
||||
|
||||
1. **Add Site**: Go to aaPanel -> Website -> Add site. Enter your domain (e.g., `sisvietnam.vn`) and select **Static** for the PHP version.
|
||||
2. **Setup Reverse Proxy**: Click "Settings" for the site -> "Reverse proxy" -> "Add reverse proxy".
|
||||
- **Proxy name**: `JavaProxy`
|
||||
- **Target URL**: `http://127.0.0.1:8080`
|
||||
- **Sent Domain**: `$host`
|
||||
3. **Spring Boot Proxy Trust**: Ensure Spring Boot knows it is behind a proxy so it can read client IPs correctly. In `src/main/resources/config/application-prod.yml`, verify this exists:
|
||||
```yaml
|
||||
server:
|
||||
forward-headers-strategy: framework
|
||||
```
|
||||
4. **SSL**: Use aaPanel's built-in SSL manager to apply Let's Encrypt certificates to your NGINX site. You don't need to configure SSL inside Spring Boot itself.
|
||||
@@ -1,49 +0,0 @@
|
||||
const fs = require('fs');
|
||||
|
||||
const aboutPath = 'd:\\website_sisvietnam_moi\\website_sisvietnam.vn\\sisvietnamvn\\src\\main\\resources\\templates\\about.html';
|
||||
const layoutPath = 'd:\\website_sisvietnam_moi\\website_sisvietnam.vn\\sisvietnamvn\\src\\main\\resources\\templates\\fragments\\layout.html';
|
||||
const footerPath = 'd:\\website_sisvietnam_moi\\website_sisvietnam.vn\\sisvietnamvn\\src\\main\\resources\\templates\\fragments\\footer.html';
|
||||
|
||||
let aboutHtml = fs.readFileSync(aboutPath, 'utf8');
|
||||
let layoutHtml = fs.readFileSync(layoutPath, 'utf8');
|
||||
|
||||
// 1. Extract Head
|
||||
const headMatch = aboutHtml.match(/<head>([\s\S]*?)<\/head>/i);
|
||||
const headContent = headMatch ? headMatch[1] : '';
|
||||
|
||||
// 2. Extract Main Content (everything between </header> and <footer ...>)
|
||||
const mainMatch = aboutHtml.match(/<\/header>([\s\S]*?)<footer/i);
|
||||
let mainContent = mainMatch ? mainMatch[1] : '';
|
||||
// The match stops at `<footer`, so it doesn't include it.
|
||||
|
||||
// 3. Extract Footer (from <footer id="l--main-footer"... to </footer>)
|
||||
const footerMatch = aboutHtml.match(/(<footer id="l--main-footer"[\s\S]*?<\/footer>)/i);
|
||||
let footerContent = footerMatch ? footerMatch[1] : '';
|
||||
|
||||
// Create footer.html with fragment
|
||||
footerContent = footerContent.replace('<footer id="l--main-footer" class="site-footer">', '<footer id="l--main-footer" class="site-footer" th:fragment="footer">');
|
||||
fs.writeFileSync(footerPath, footerContent, 'utf8');
|
||||
|
||||
// Update layout.html to include footer
|
||||
layoutHtml = layoutHtml.replace(/<footer>[\s\S]*?<\/footer>/i, '<footer th:replace="~{fragments/footer :: footer}"></footer>');
|
||||
fs.writeFileSync(layoutPath, layoutHtml, 'utf8');
|
||||
|
||||
// Construct new about.html
|
||||
const newAboutHtml = `<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{fragments/layout}">
|
||||
<head>
|
||||
<th:block layout:fragment="head">
|
||||
${headContent}
|
||||
</th:block>
|
||||
</head>
|
||||
<body>
|
||||
<div layout:fragment="content" class="dialog-off-canvas-main-canvas umass-platform-homepage path-node page-node-type-landing-page landing-page transparent-header" data-off-canvas-main-canvas="">
|
||||
${mainContent}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
fs.writeFileSync(aboutPath, newAboutHtml, 'utf8');
|
||||
|
||||
console.log("Transformation completed successfully!");
|
||||
+100
-18
@@ -1,32 +1,114 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'org.springframework.boot' version '4.0.6'
|
||||
id 'io.spring.dependency-management' version '1.1.7'
|
||||
id "java"
|
||||
id "maven-publish"
|
||||
id "idea"
|
||||
id "eclipse"
|
||||
alias(libs.plugins.gradle.git.properties)
|
||||
alias(libs.plugins.spring.boot)
|
||||
id "jhipster.docker-conventions"
|
||||
id "jhipster.code-quality-conventions"
|
||||
id "org.liquibase.gradle"
|
||||
// jhipster-needle-gradle-plugins - JHipster will add additional gradle plugins here
|
||||
}
|
||||
|
||||
group = 'com.example'
|
||||
version = '0.0.1-SNAPSHOT'
|
||||
group = "com.sisvietnamvn.web"
|
||||
version = "1.0.4"
|
||||
|
||||
description = ""
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(21)
|
||||
}
|
||||
sourceCompatibility=21
|
||||
targetCompatibility=21
|
||||
}
|
||||
assert System.properties["java.specification.version"] == "21" || "25"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenCentral()
|
||||
// Local maven repository is required for libraries built locally with maven like development jhipster-bom.
|
||||
// mavenLocal()
|
||||
// jhipster-needle-gradle-repositories - JHipster will add additional repositories
|
||||
}
|
||||
|
||||
apply from: "gradle/spring-boot.gradle"
|
||||
apply from: "gradle/liquibase.gradle"
|
||||
// jhipster-needle-gradle-apply-from - JHipster will add additional gradle scripts to be applied here
|
||||
|
||||
idea {
|
||||
module {
|
||||
excludeDirs += files("node_modules")
|
||||
}
|
||||
}
|
||||
|
||||
// eclipse {
|
||||
// sourceSets {
|
||||
// main {
|
||||
// java {
|
||||
// srcDirs += ["build/generated/sources/annotationProcessor/java/main"]
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
|
||||
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-webmvc'
|
||||
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-thymeleaf-test'
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-webmvc-test'
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
implementation libs.jhipster.framework
|
||||
implementation libs.mapstruct
|
||||
implementation libs.springdoc.openapi.starter.webmvc.api
|
||||
implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:3.0.3"
|
||||
implementation "org.springframework.boot:spring-boot-h2console"
|
||||
implementation "org.springframework.boot:spring-boot-jackson2"
|
||||
implementation "org.springframework.boot:spring-boot-starter"
|
||||
implementation "org.springframework.boot:spring-boot-starter-actuator"
|
||||
implementation "org.springframework.boot:spring-boot-starter-aspectj"
|
||||
implementation "org.springframework.boot:spring-boot-starter-cache"
|
||||
implementation "org.springframework.boot:spring-boot-starter-data-jpa"
|
||||
implementation "org.springframework.boot:spring-boot-starter-jackson"
|
||||
implementation "org.springframework.boot:spring-boot-starter-liquibase"
|
||||
implementation "org.springframework.boot:spring-boot-starter-mail"
|
||||
implementation "org.springframework.boot:spring-boot-starter-oauth2-resource-server"
|
||||
implementation "org.springframework.boot:spring-boot-starter-security"
|
||||
implementation "org.springframework.boot:spring-boot-starter-thymeleaf"
|
||||
implementation "nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect"
|
||||
implementation "org.springframework.boot:spring-boot-starter-tomcat"
|
||||
implementation "org.springframework.boot:spring-boot-starter-validation"
|
||||
implementation "org.springframework.boot:spring-boot-starter-web"
|
||||
implementation "org.springframework.security:spring-security-data"
|
||||
implementation "com.fasterxml.jackson.datatype:jackson-datatype-hppc"
|
||||
implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310"
|
||||
implementation "com.zaxxer:HikariCP"
|
||||
implementation "io.micrometer:micrometer-registry-prometheus"
|
||||
implementation "javax.cache:cache-api"
|
||||
implementation "org.apache.commons:commons-lang3"
|
||||
implementation "org.ehcache:ehcache::jakarta"
|
||||
implementation "org.hibernate.orm:hibernate-core"
|
||||
implementation "org.hibernate.orm:hibernate-jcache"
|
||||
implementation "org.hibernate.validator:hibernate-validator"
|
||||
implementation "tools.jackson.datatype:jackson-datatype-hibernate7"
|
||||
implementation "tools.jackson.module:jackson-module-jaxb-annotations"
|
||||
testImplementation(libs.archunit.junit5.api) {
|
||||
exclude group: 'org.slf4j', module: 'slf4j-api'
|
||||
}
|
||||
testImplementation "org.springframework.boot:spring-boot-starter-jackson-test"
|
||||
testImplementation "org.springframework.boot:spring-boot-starter-security-test"
|
||||
testImplementation "org.springframework.boot:spring-boot-starter-test"
|
||||
testImplementation "org.springframework.boot:spring-boot-starter-webmvc-test"
|
||||
testImplementation "org.springframework.boot:spring-boot-test"
|
||||
testImplementation "org.springframework.security:spring-security-test"
|
||||
testImplementation "org.testcontainers:testcontainers"
|
||||
testImplementation "org.testcontainers:testcontainers-jdbc"
|
||||
testImplementation "org.testcontainers:testcontainers-junit-jupiter"
|
||||
testRuntimeOnly(libs.archunit.junit5.engine) {
|
||||
exclude group: 'org.slf4j', module: 'slf4j-api'
|
||||
}
|
||||
annotationProcessor libs.mapstruct.processor
|
||||
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
|
||||
annotationProcessor "org.glassfish.jaxb:jaxb-runtime"
|
||||
annotationProcessor "org.hibernate.orm:hibernate-processor"
|
||||
// jhipster-needle-gradle-dependency - JHipster will add additional dependencies here
|
||||
}
|
||||
|
||||
tasks.named('test') {
|
||||
useJUnitPlatform()
|
||||
tasks.register('printSourceSets') {
|
||||
doLast {
|
||||
println "classesDirs = ${sourceSets.main.output.classesDirs.files}"
|
||||
println "runtimeClasspath = ${sourceSets.main.runtimeClasspath.files}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
./gradlew -Pprod clean bootJar
|
||||
@@ -0,0 +1,17 @@
|
||||
plugins {
|
||||
id 'groovy-gradle-plugin'
|
||||
}
|
||||
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation libs.jib.plugin
|
||||
implementation libs.modernizer.plugin
|
||||
implementation libs.nohttp.plugin
|
||||
implementation libs.sonarqube.plugin
|
||||
implementation libs.spotless.plugin
|
||||
// jhipster-needle-gradle-dependency - JHipster will add additional dependencies for convention plugins here
|
||||
// jhipster-needle-gradle-build-src-dependency - Deprecated: JHipster will add additional dependencies for convention plugins here
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
[versions]
|
||||
# jhipster-needle-gradle-dependency-catalog-version - JHipster will add additional versions for convention plugins here
|
||||
# jhipster-needle-gradle-build-src-dependency-catalog-version - Deprecated: JHipster will add additional versions for convention plugins here
|
||||
|
||||
[libraries]
|
||||
jib-plugin = { module = "com.google.cloud.tools:jib-gradle-plugin", version = "3.5.3" }
|
||||
modernizer-plugin = { module = "com.github.andygoossens:gradle-modernizer-plugin", version = "1.13.0" }
|
||||
nohttp-plugin = { module = "io.spring.nohttp:nohttp-gradle", version = "0.0.11" }
|
||||
sonarqube-plugin = { module = "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin", version = "7.3.0.8198" }
|
||||
spotless-plugin = { module = "com.diffplug.spotless:spotless-plugin-gradle", version = "8.5.1" }
|
||||
# jhipster-needle-gradle-dependency-catalog-libraries - JHipster will add additional libraries versions
|
||||
|
||||
[plugins]
|
||||
# jhipster-needle-gradle-dependency-catalog-plugins - JHipster will add additional plugins versions
|
||||
@@ -0,0 +1,64 @@
|
||||
plugins {
|
||||
id "jacoco"
|
||||
id "org.sonarqube"
|
||||
id "com.diffplug.spotless"
|
||||
id "com.github.andygoossens.gradle-modernizer-plugin"
|
||||
id "io.spring.nohttp"
|
||||
}
|
||||
|
||||
jacoco {
|
||||
toolVersion = "${libs.versions.jacoco.get()}"
|
||||
}
|
||||
|
||||
jacocoTestReport {
|
||||
executionData(tasks.withType(Test))
|
||||
classDirectories.from = files(sourceSets.main.output.classesDirs)
|
||||
sourceDirectories.from = files(sourceSets.main.java.srcDirs)
|
||||
|
||||
reports {
|
||||
xml.required = true
|
||||
}
|
||||
}
|
||||
|
||||
file("sonar-project.properties").withReader {
|
||||
Properties sonarProperties = new Properties()
|
||||
sonarProperties.load(it)
|
||||
|
||||
sonarProperties.each { key, value ->
|
||||
sonarqube {
|
||||
properties {
|
||||
property(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spotless {
|
||||
java {
|
||||
target 'src/*/java/**/*.java'
|
||||
// removeUnusedImports()
|
||||
}
|
||||
}
|
||||
|
||||
modernizer {
|
||||
failOnViolations = true
|
||||
includeTestClasses = true
|
||||
}
|
||||
|
||||
checkstyle {
|
||||
toolVersion = "${libs.versions.checkstyle.get()}"
|
||||
configFile = file("checkstyle.xml")
|
||||
ignoreFailures = true
|
||||
checkstyleTest.enabled = false
|
||||
}
|
||||
|
||||
nohttp {
|
||||
source.include("build.gradle", "README.md")
|
||||
}
|
||||
|
||||
// workaround for https://github.com/checkstyle/checkstyle/issues/14123
|
||||
configurations.checkstyle {
|
||||
resolutionStrategy.capabilitiesResolution.withCapability("com.google.collections:google-collections") {
|
||||
select("com.google.guava:guava:0")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
plugins {
|
||||
id "com.google.cloud.tools.jib"
|
||||
}
|
||||
|
||||
jib {
|
||||
configurationName = "productionRuntimeClasspath"
|
||||
from {
|
||||
image = "eclipse-temurin:25-jre-noble"
|
||||
platforms {
|
||||
platform {
|
||||
architecture = "${findProperty('jibArchitecture') ?: 'amd64'}"
|
||||
os = "linux"
|
||||
}
|
||||
}
|
||||
}
|
||||
to {
|
||||
image = "sisvietnamvn:latest"
|
||||
}
|
||||
container {
|
||||
entrypoint = ["bash", "-c", "/entrypoint.sh"]
|
||||
ports = ["8080"]
|
||||
environment = [
|
||||
SPRING_OUTPUT_ANSI_ENABLED: "ALWAYS",
|
||||
JHIPSTER_SLEEP: "0"
|
||||
]
|
||||
creationTime = "USE_CURRENT_TIMESTAMP"
|
||||
user = 1000
|
||||
}
|
||||
extraDirectories {
|
||||
paths = file("src/main/docker/jib")
|
||||
permissions = ["/entrypoint.sh": "755"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
|
||||
"https://checkstyle.org/dtds/configuration_1_3.dtd">
|
||||
<module name="Checker">
|
||||
|
||||
<!-- Configure checker to use UTF-8 encoding -->
|
||||
<property name="charset" value="UTF-8"/>
|
||||
<!-- Configure checker to run on files with these extensions -->
|
||||
<property name="fileExtensions" value=""/>
|
||||
<!-- For detailed checkstyle configuration, see https://github.com/spring-io/nohttp/tree/master/nohttp-checkstyle -->
|
||||
<module name="io.spring.nohttp.checkstyle.check.NoHttpCheck">
|
||||
</module>
|
||||
<module name="TreeWalker">
|
||||
<module name="MissingJavadocMethod">
|
||||
<!-- Disable Javadoc requirement as we want to follow "clean code" guidelines and classes, methods and arguments names should be self-explanatory -->
|
||||
<property name="allowMissingPropertyJavadoc" value="true"/>
|
||||
</module>
|
||||
</module>
|
||||
<!-- Allow suppression with comments
|
||||
// CHECKSTYLE:OFF
|
||||
... ignored content ...
|
||||
// CHECKSTYLE:ON
|
||||
-->
|
||||
<module name="SuppressWithPlainTextCommentFilter"/>
|
||||
</module>
|
||||
@@ -1,14 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const path = 'd:\\website_sisvietnam_moi\\website_sisvietnam.vn\\sisvietnamvn\\src\\main\\resources\\templates\\about.html';
|
||||
|
||||
let content = fs.readFileSync(path, 'utf8');
|
||||
|
||||
// Replace UMass Undergraduate specific files with the ones from the main UMass Amherst folder if we want, or just leave it.
|
||||
// But since the folder was created while bootRun is active, let's use a gradle command to process resources.
|
||||
// However, fixing the image links is important.
|
||||
content = content.replace(/\/sites\/default\/files\/styles\/[^"'\s]+/gi, '/images/LogoSIS.svg');
|
||||
|
||||
// Also fix manifest 404
|
||||
content = content.replace(/<link rel="manifest" href="[^"]+">/gi, '');
|
||||
|
||||
fs.writeFileSync(path, content, 'utf8');
|
||||
@@ -1,5 +0,0 @@
|
||||
$path = 'd:\website_sisvietnam_moi\website_sisvietnam.vn\sisvietnamvn\src\main\resources\templates\about.html'
|
||||
$content = Get-Content -Raw -Path $path -Encoding UTF8
|
||||
$content = $content -replace '/sites/default/files/styles/[^"''\s]+', '/images/LogoSIS.svg'
|
||||
$content = $content -replace '<link rel="manifest" href="[^"]+">', ''
|
||||
Set-Content -Path $path -Value $content -Encoding UTF8
|
||||
@@ -0,0 +1,39 @@
|
||||
rootProject.name=sisvietnamvn
|
||||
profile=dev
|
||||
|
||||
liquibaseVersion=5.0.2
|
||||
liquibaseTaskPrefix=liquibase
|
||||
liquibasePluginVersion=3.1.0
|
||||
# jhipster-needle-gradle-property - JHipster will add additional properties here
|
||||
|
||||
## below are some of the gradle performance improvement settings that can be used as required, these are not enabled by default
|
||||
|
||||
## The Gradle daemon aims to improve the startup and execution time of Gradle.
|
||||
## The daemon is enabled by default in Gradle 3+ setting this to false will disable this.
|
||||
## https://docs.gradle.org/current/userguide/gradle_daemon.html#sec:ways_to_disable_gradle_daemon
|
||||
## uncomment the below line to disable the daemon
|
||||
|
||||
#org.gradle.daemon=false
|
||||
|
||||
## Specifies the JVM arguments used for the daemon process.
|
||||
## The setting is particularly useful for tweaking memory settings.
|
||||
## Default value: -Xmx1024m -XX:MaxPermSize=256m
|
||||
## uncomment the below line to override the daemon defaults
|
||||
|
||||
#org.gradle.jvmargs=-Xmx1024m -XX:MaxPermSize=256m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||
|
||||
## When configured, Gradle will run in incubating parallel mode.
|
||||
## This option should only be used with decoupled projects. More details, visit
|
||||
## http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
## uncomment the below line to enable parallel mode
|
||||
|
||||
#org.gradle.parallel=true
|
||||
|
||||
## Enables new incubating mode that makes Gradle selective when configuring projects.
|
||||
## Only relevant projects are configured which results in faster builds for large multi-projects.
|
||||
## http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:configuration_on_demand
|
||||
## uncomment the below line to enable the selective mode
|
||||
|
||||
#org.gradle.configureondemand=true
|
||||
|
||||
org.gradle.warning.mode=all
|
||||
@@ -0,0 +1,20 @@
|
||||
[versions]
|
||||
mapstruct = "1.6.3"
|
||||
archunit-junit5 = "1.4.2"
|
||||
checkstyle = "13.4.2"
|
||||
jacoco = "0.8.14"
|
||||
# jhipster-needle-gradle-dependency-catalog-version - JHipster will add additional versions for convention plugins here
|
||||
|
||||
[libraries]
|
||||
jhipster-framework = { module = "tech.jhipster:jhipster-framework", version = "9.1.0" }
|
||||
springdoc-openapi-starter-webmvc-api = { module = "org.springdoc:springdoc-openapi-starter-webmvc-api", version = "3.0.3" }
|
||||
archunit-junit5-api = { module = "com.tngtech.archunit:archunit-junit5-api", version.ref = "archunit-junit5" }
|
||||
archunit-junit5-engine = { module = "com.tngtech.archunit:archunit-junit5-engine", version.ref = "archunit-junit5" }
|
||||
mapstruct = { module = "org.mapstruct:mapstruct", version.ref = "mapstruct" }
|
||||
mapstruct-processor = { module = "org.mapstruct:mapstruct-processor", version.ref = "mapstruct" }
|
||||
# jhipster-needle-gradle-dependency-catalog-libraries - JHipster will add additional libraries versions
|
||||
|
||||
[plugins]
|
||||
gradle-git-properties = { id = "com.gorylenko.gradle-git-properties", version = "3.0.3" }
|
||||
spring-boot = { id = "org.springframework.boot", version = "4.0.6" }
|
||||
# jhipster-needle-gradle-dependency-catalog-plugins - JHipster will add additional plugins versions
|
||||
@@ -0,0 +1,53 @@
|
||||
configurations {
|
||||
liquibaseRuntime.extendsFrom sourceSets.main.compileClasspath
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "org.liquibase:liquibase-core"
|
||||
liquibaseRuntime "org.liquibase:liquibase-core"
|
||||
// Dependency required to parse options. Refer to https://github.com/liquibase/liquibase-gradle-plugin/tree/Release_2.2.0#news.
|
||||
liquibaseRuntime "info.picocli:picocli:4.7.7"
|
||||
if (project.hasProperty("prod") || project.hasProperty("gae")) {
|
||||
liquibaseRuntime "com.oracle.database.jdbc:ojdbc8"
|
||||
}
|
||||
liquibaseRuntime "org.liquibase.ext:liquibase-hibernate6:${liquibaseVersion}"
|
||||
// jhipster-needle-gradle-dependency - JHipster will add additional dependencies here
|
||||
}
|
||||
|
||||
project.ext.diffChangelogFile = "src/main/resources/config/liquibase/changelog/" + new Date().format("yyyyMMddHHmmss") + "_changelog.xml"
|
||||
if (!project.hasProperty("runList")) {
|
||||
project.ext.runList = "main"
|
||||
}
|
||||
|
||||
liquibase {
|
||||
activities {
|
||||
main {
|
||||
driver "org.h2.Driver"
|
||||
url "jdbc:h2:file:./build/h2db/db/sisvietnamvn"
|
||||
username "sisvietnamvn"
|
||||
changelogFile "src/main/resources/config/liquibase/master.xml"
|
||||
logLevel "debug"
|
||||
classpath "src/main/resources/"
|
||||
}
|
||||
diffLog {
|
||||
driver "org.h2.Driver"
|
||||
url "jdbc:h2:file:./build/h2db/db/sisvietnamvn"
|
||||
username "sisvietnamvn"
|
||||
changelogFile project.ext.diffChangelogFile
|
||||
referenceUrl "hibernate:spring:com.sisvietnamvn.web.domain?dialect=org.hibernate.dialect.H2Dialect&hibernate.physical_naming_strategy=org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy&hibernate.implicit_naming_strategy=org.springframework.boot.hibernate.SpringImplicitNamingStrategy"
|
||||
logLevel "debug"
|
||||
classpath layout.buildDirectory.dir("classes/java/main").get().asFile.absolutePath
|
||||
}
|
||||
}
|
||||
|
||||
runList = project.ext.runList
|
||||
}
|
||||
|
||||
tasks.named('liquibaseDiff').configure { dependsOn(tasks.named('compileJava')) }
|
||||
tasks.named('liquibaseDiffChangelog').configure { dependsOn(tasks.named('compileJava')) }
|
||||
|
||||
ext {
|
||||
if (project.hasProperty("no-liquibase")) {
|
||||
springProfiles += ",no-liquibase"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
dependencies {
|
||||
developmentOnly "org.springframework.boot:spring-boot-devtools"
|
||||
implementation "com.h2database:h2"
|
||||
// jhipster-needle-gradle-dependency - JHipster will add additional dependencies here
|
||||
}
|
||||
|
||||
springBoot {
|
||||
buildInfo {
|
||||
excludes = ['time']
|
||||
}
|
||||
}
|
||||
|
||||
bootRun {
|
||||
args = ["--spring.profiles.active=${springProfiles}"]
|
||||
}
|
||||
|
||||
|
||||
processResources {
|
||||
inputs.property('version', version)
|
||||
inputs.property('springProfiles', springProfiles)
|
||||
filesMatching("**/application.yml") {
|
||||
filter {
|
||||
it.replace("@project.version@", version)
|
||||
}
|
||||
filter {
|
||||
it.replace("@spring.profiles.active@", springProfiles)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def integrationTest = tasks.register('integrationTest', Test) {
|
||||
maxHeapSize = "1G"
|
||||
useJUnitPlatform()
|
||||
description = "Execute integration tests."
|
||||
group = "verification"
|
||||
include "**/*IT*", "**/*IntTest*"
|
||||
testLogging {
|
||||
events = ['FAILED', 'SKIPPED']
|
||||
exceptionFormat = "full"
|
||||
}
|
||||
systemProperty('spring.profiles.active', springTestProfiles)
|
||||
// uncomment if the tests reports are not generated
|
||||
// see https://github.com/jhipster/generator-jhipster/pull/2771 and https://github.com/jhipster/generator-jhipster/pull/4484
|
||||
// ignoreFailures true
|
||||
reports.html.required = false
|
||||
dependsOn(tasks.named('test'))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
dependencies {
|
||||
implementation "com.oracle.database.jdbc:ojdbc8"
|
||||
testImplementation "org.testcontainers:testcontainers-oracle-xe"
|
||||
// jhipster-needle-gradle-dependency - JHipster will add additional dependencies here
|
||||
}
|
||||
|
||||
ext {
|
||||
if (project.hasProperty("api-docs")) {
|
||||
springProfiles += ",api-docs"
|
||||
}
|
||||
}
|
||||
|
||||
springBoot {
|
||||
buildInfo()
|
||||
}
|
||||
|
||||
bootRun {
|
||||
args = ["--spring.profiles.active=${springProfiles}"]
|
||||
}
|
||||
|
||||
|
||||
processResources {
|
||||
inputs.property('version', version)
|
||||
inputs.property('springProfiles', springProfiles)
|
||||
filesMatching("**/application.yml") {
|
||||
filter {
|
||||
it.replace("@project.version@", version)
|
||||
}
|
||||
filter {
|
||||
it.replace("@spring.profiles.active@", springProfiles)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def integrationTest = tasks.register('integrationTest', Test) {
|
||||
maxHeapSize = "1G"
|
||||
useJUnitPlatform()
|
||||
description = "Execute integration tests."
|
||||
group = "verification"
|
||||
include "**/*IT*", "**/*IntTest*"
|
||||
testLogging {
|
||||
events = ['FAILED', 'SKIPPED']
|
||||
exceptionFormat = "full"
|
||||
}
|
||||
systemProperty('spring.profiles.active', springTestProfiles)
|
||||
// uncomment if the tests reports are not generated
|
||||
// see https://github.com/jhipster/generator-jhipster/pull/2771 and https://github.com/jhipster/generator-jhipster/pull/4484
|
||||
// ignoreFailures true
|
||||
reports.html.required = false
|
||||
dependsOn(tasks.named('test'))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
ext {
|
||||
if (project.hasProperty("prod")) {
|
||||
springProfiles = "prod"
|
||||
springTestProfiles = "test,testprod"
|
||||
} else {
|
||||
springProfiles = "dev"
|
||||
springTestProfiles = "test,testdev"
|
||||
}
|
||||
if (project.hasProperty("tls")) {
|
||||
springProfiles += ",tls"
|
||||
}
|
||||
if (project.hasProperty("e2e")) {
|
||||
springProfiles += ",e2e"
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'io.spring.dependency-management'
|
||||
|
||||
// jhipster-needle-gradle-apply-from - JHipster will add additional gradle scripts to be applied here
|
||||
|
||||
if (project.hasProperty("prod")) {
|
||||
apply from: "gradle/profile_prod.gradle"
|
||||
} else {
|
||||
apply from: "gradle/profile_dev.gradle"
|
||||
}
|
||||
|
||||
if (project.hasProperty("war")) {
|
||||
apply from: "gradle/war.gradle"
|
||||
}
|
||||
|
||||
|
||||
defaultTasks "bootRun"
|
||||
|
||||
springBoot {
|
||||
mainClass = "com.sisvietnamvn.web.SisvietnamvnApp"
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
exclude "**/*IT*", "**/*IntTest*"
|
||||
testLogging {
|
||||
events = ['FAILED', 'SKIPPED']
|
||||
exceptionFormat = "full"
|
||||
}
|
||||
jvmArgs += '-Xmx512m'
|
||||
|
||||
systemProperty('spring.profiles.active', springTestProfiles)
|
||||
|
||||
// uncomment if the tests reports are not generated
|
||||
// see https://github.com/jhipster/generator-jhipster/pull/2771 and https://github.com/jhipster/generator-jhipster/pull/4484
|
||||
// ignoreFailures true
|
||||
reports.html.required = false
|
||||
}
|
||||
|
||||
tasks.named('check').configure { dependsOn(tasks.named('integrationTest')) }
|
||||
|
||||
tasks.register('testReport', TestReport) {
|
||||
destinationDirectory = layout.buildDirectory.dir("reports/tests")
|
||||
testResults.from(test)
|
||||
}
|
||||
|
||||
tasks.register('integrationTestReport', TestReport) {
|
||||
destinationDirectory = layout.buildDirectory.dir("reports/tests")
|
||||
testResults.from(tasks.named('integrationTest'))
|
||||
}
|
||||
|
||||
gitProperties {
|
||||
failOnNoGitDirectory = false
|
||||
keys = ["git.branch", "git.commit.id.abbrev", "git.commit.id.describe"]
|
||||
}
|
||||
|
||||
tasks.named('generateGitProperties') {
|
||||
outputs.doNotCacheIf("Task is always executed") { true }
|
||||
}
|
||||
|
||||
tasks.register('cleanResources', Delete) {
|
||||
delete "build/resources"
|
||||
}
|
||||
|
||||
tasks.named('compileJava').configure { dependsOn(tasks.named('processResources')) }
|
||||
tasks.named('processResources').configure { dependsOn(tasks.named('bootBuildInfo')) }
|
||||
@@ -0,0 +1,12 @@
|
||||
apply plugin: "war"
|
||||
|
||||
bootWar {
|
||||
mainClass = "com.sisvietnamvn.web.SisvietnamvnApp"
|
||||
includes = ["WEB-INF/**", "META-INF/**"]
|
||||
}
|
||||
|
||||
war {
|
||||
enabled = true
|
||||
archiveExtension = "war.original"
|
||||
includes = ["WEB-INF/**", "META-INF/**"]
|
||||
}
|
||||
BIN
Binary file not shown.
+1
-3
@@ -1,7 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
dependencies {
|
||||
implementation "io.micrometer:micrometer-tracing-bridge-brave"
|
||||
implementation "io.zipkin.reporter2:zipkin-reporter-brave"
|
||||
}
|
||||
Vendored
+15
-18
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015 the original authors.
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -15,8 +15,6 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
@@ -57,7 +55,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
@@ -85,8 +83,7 @@ done
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@@ -114,6 +111,7 @@ case "$( uname )" in #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
@@ -132,13 +130,10 @@ location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
@@ -146,7 +141,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
@@ -154,7 +149,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
@@ -171,6 +166,7 @@ fi
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
@@ -202,15 +198,16 @@ fi
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
|
||||
Vendored
+12
-13
@@ -13,8 +13,6 @@
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@@ -45,11 +43,11 @@ set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
@@ -59,21 +57,22 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
|
||||
Generated
+7382
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"name": "sisvietnamvn",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"description": "Description for sisvietnamvn",
|
||||
"license": "UNLICENSED",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"app:start": "./gradlew",
|
||||
"app:up": "docker compose -f src/main/docker/app.yml up --wait",
|
||||
"backend:build-cache": "npm run backend:info && npm run backend:nohttp:test && npm run ci:e2e:package -- -x webapp -x webapp_test",
|
||||
"backend:doc:test": "./gradlew javadoc ",
|
||||
"backend:info": "./gradlew -v",
|
||||
"backend:nohttp:test": "./gradlew checkstyleNohttp ",
|
||||
"backend:start": "./gradlew ",
|
||||
"backend:unit:test": "./gradlew test integrationTest -Dlogging.level.ROOT=OFF -Dlogging.level.tech.jhipster=OFF -Dlogging.level.com.sisvietnamvn.web=OFF -Dlogging.level.org.springframework=OFF -Dlogging.level.org.springframework.web=OFF -Dlogging.level.org.springframework.security=OFF",
|
||||
"ci:backend:test": "npm run backend:info && npm run backend:doc:test && npm run backend:nohttp:test && npm run backend:unit:test -- -P$npm_package_config_default_environment",
|
||||
"ci:e2e:package": "npm run java:$npm_package_config_packaging:$npm_package_config_default_environment -- -Pe2e -Denforcer.skip=true",
|
||||
"postci:e2e:package": "cp build/libs/*.$npm_package_config_packaging e2e.$npm_package_config_packaging",
|
||||
"ci:e2e:prepare": "npm run ci:e2e:prepare:docker",
|
||||
"ci:e2e:prepare:docker": "npm run services:up --if-present && docker ps -a",
|
||||
"preci:e2e:server:start": "npm run services:db:await --if-present && npm run services:others:await --if-present",
|
||||
"ci:e2e:server:start": "java -jar e2e.$npm_package_config_packaging --spring.profiles.active=e2e,secret-samples,$npm_package_config_default_environment -Dlogging.level.ROOT=OFF -Dlogging.level.tech.jhipster=OFF -Dlogging.level.com.sisvietnamvn.web=OFF -Dlogging.level.org.springframework=OFF -Dlogging.level.org.springframework.web=OFF -Dlogging.level.org.springframework.security=OFF --logging.level.org.springframework.web=ERROR",
|
||||
"ci:e2e:teardown": "npm run ci:e2e:teardown:docker --if-present",
|
||||
"ci:server:await": "echo \"Waiting for server at port $npm_package_config_backend_port to start\" && wait-on -t 180000 http-get://127.0.0.1:$npm_package_config_backend_port/management/health && echo \"Server at port $npm_package_config_backend_port started\"",
|
||||
"docker:db:up": "echo \"Docker for db oracle not configured for application sisvietnamvn\"",
|
||||
"java:docker": "./gradlew bootJar -Pprod jibDockerBuild",
|
||||
"java:docker:arm64": "npm run java:docker -- -PjibArchitecture=arm64",
|
||||
"java:docker:dev": "npm run java:docker -- -Pdev,webapp",
|
||||
"java:docker:prod": "npm run java:docker -- -Pprod",
|
||||
"java:jar": "./gradlew bootJar -x test -x integrationTest",
|
||||
"java:jar:dev": "npm run java:jar -- -Pdev,webapp",
|
||||
"java:jar:prod": "npm run java:jar -- -Pprod",
|
||||
"java:war": "./gradlew bootWar -Pwar -x test -x integrationTest",
|
||||
"java:war:dev": "npm run java:war -- -Pdev,webapp",
|
||||
"java:war:prod": "npm run java:war -- -Pprod"
|
||||
},
|
||||
"config": {
|
||||
"backend_port": 8080,
|
||||
"default_environment": "prod",
|
||||
"packaging": "jar"
|
||||
},
|
||||
"devDependencies": {
|
||||
"generator-jhipster": "9.1.0",
|
||||
"prettier": "3.8.3",
|
||||
"prettier-plugin-java": "2.9.6",
|
||||
"prettier-plugin-packagejson": "3.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=24.16.0"
|
||||
}
|
||||
}
|
||||
@@ -1 +1,20 @@
|
||||
rootProject.name = 'sisvietnamvn'
|
||||
|
||||
pluginManagement {
|
||||
repositories {
|
||||
// jhipster-needle-gradle-plugin-management-repositories - JHipster will add additional entries here
|
||||
}
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.liquibase:liquibase-core:${liquibaseVersion}"
|
||||
}
|
||||
}
|
||||
plugins {
|
||||
id "org.liquibase.gradle" version "${liquibasePluginVersion}"
|
||||
// jhipster-needle-gradle-plugin-management-plugins - JHipster will add additional entries here
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "sisvietnamvn"
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
# TÀI LIỆU YÊU CẦU WEBSITE BỆNH VIỆN S.I.S CẦN THƠ
|
||||
*(Trích xuất từ file WEBSITE BENH VIEN.xlsx)*
|
||||
|
||||
Tài liệu này đóng vai trò là kim chỉ nam cho Developer (IDE Code) để thiết kế kiến trúc hệ thống, cơ sở dữ liệu và giao diện người dùng cho Website Bệnh viện Đa khoa Quốc tế S.I.S Cần Thơ.
|
||||
|
||||
---
|
||||
|
||||
## 1. TỔNG QUAN DỰ ÁN
|
||||
### 1.1. Đối tượng khách hàng mục tiêu
|
||||
* **Độ tuổi:** Trung niên (Từ 30 - 60 tuổi). Do đó, UI/UX cần rõ ràng, dễ nhìn, chữ to, dễ thao tác.
|
||||
* **Hành vi:** Có nhu cầu và quan tâm đặc biệt đến việc chăm sóc sức khỏe đối với các bệnh: **Đột quỵ, Tim mạch, Cơ xương khớp**.
|
||||
|
||||
### 1.2. Mục đích cốt lõi của Website
|
||||
1. Cung cấp thông tin Giới thiệu về Dịch vụ Bệnh viện.
|
||||
2. Quảng bá thương hiệu S.I.S.
|
||||
3. Đẩy mạnh các chiến dịch PR & Marketing trực tuyến.
|
||||
4. Cung cấp kiến thức giáo dục sức khỏe cộng đồng.
|
||||
|
||||
---
|
||||
|
||||
## 2. YÊU CẦU THIẾT KẾ VÀ KỸ THUẬT (TECHNICAL SPECS)
|
||||
* **Ngôn ngữ:** Hỗ trợ Song ngữ (Tiếng Anh - Tiếng Việt). Cần thiết lập cấu trúc i18n cho Frontend.
|
||||
* **Bố cục (Layout):**
|
||||
* Chia cột rõ ràng (Trái / Phải).
|
||||
* **Cột trái:** Hiển thị luồng Tin tức Bệnh viện.
|
||||
* **Cột phải:** Hiển thị các Banner Gói khám nổi bật hoặc Chương trình Khuyến mãi mới nhất.
|
||||
* **Đa phương tiện:** Tích hợp âm thanh vào các Banner/Cover chính.
|
||||
* **Tính năng lõi:**
|
||||
* **Tích hợp cổng Thanh toán trực tuyến** (VNPAY, Paypal... do Kế toán và IT quyết định).
|
||||
* Check chính tả tự động.
|
||||
* **Tối ưu hóa (SEO & Performance):**
|
||||
* Tốc độ tải trang nhanh (Cần tối ưu dung lượng ảnh Slider/Banner).
|
||||
* Truy xuất dữ liệu chuẩn SEO và tích hợp Google Analytics, Google Search Console.
|
||||
|
||||
---
|
||||
|
||||
## 3. CẤU TRÚC SITEMAP & TÍNH NĂNG CHI TIẾT
|
||||
|
||||
### I. VỀ CHÚNG TÔI
|
||||
Trọng tâm sử dụng đồ họa trực quan (Infographic) để gây ấn tượng.
|
||||
* **Giới thiệu Bệnh viện:** Thông tin Ban giám đốc.
|
||||
* **Giá trị cốt lõi / Tầm nhìn / Sứ mệnh**
|
||||
* **Lịch sử hình thành:** Hiển thị dưới dạng Infographic **Chuỗi thời gian (Timeline)**.
|
||||
* **Giải thưởng:** Hiển thị dưới dạng Infographic Chuỗi thời gian. Cập nhật liên tục.
|
||||
* **Sơ đồ tổ chức:** Hiển thị dưới dạng Infographic **Mạng lưới (Network/Tree)**.
|
||||
|
||||
### II. DỊCH VỤ BỆNH VIỆN
|
||||
* **Gói tầm soát sức khỏe:** Các trang giới thiệu gói khám riêng biệt. (Giá có thể thay đổi).
|
||||
* **Dịch vụ nổi bật:** Kỹ thuật đặt stent + coil, Hút huyết khối, Nội soi khớp/Super bath, Phẫu thuật bắt cầu động mạch cảnh, Phẫu thuật mở sọ giải áp, Phục hồi chức năng.
|
||||
* **Trang thiết bị:** MRI, DSA, Hệ thống xét nghiệm, Phòng mổ Hybrid, Cấp cứu di động + Ca nô.
|
||||
* **Tổng đài cấp cứu Đột quỵ**
|
||||
* **Đặt lịch khám:** Form cố định. Danh sách bác sĩ thay đổi theo tuần. Cần lấy dữ liệu từ hệ thống Call Center.
|
||||
* **Thanh toán trực tuyến:** Module thanh toán.
|
||||
|
||||
### III. TÌM BÁC SĨ
|
||||
Trang danh bạ Bác sĩ toàn viện. Cấu trúc Profile bác sĩ bao gồm:
|
||||
1. Họ và tên
|
||||
2. Chuyên khoa
|
||||
3. Kinh nghiệm làm việc
|
||||
4. **Hệ thống đánh giá/Review:** Khách hàng có thể để lại Nhận xét (Gồm Họ tên, SĐT, Email). Cam kết bảo mật thông tin.
|
||||
5. Nút "Đăng ký khám" trỏ về tính năng Đặt lịch.
|
||||
|
||||
### IV. CHUYÊN KHOA
|
||||
* Danh sách tất cả các chuyên khoa và phòng ban tại bệnh viện.
|
||||
|
||||
### V. GÓC KHÁCH HÀNG
|
||||
* **Giờ làm việc**
|
||||
* **Khám bệnh Ngoại trú:** Quy trình khám, Hướng dẫn BHYT, Hướng dẫn khám Dịch vụ.
|
||||
* **Điều trị Nội trú:** Dịch vụ phòng nội trú, Thông tin thăm bệnh, Thông tin nhập/xuất viện.
|
||||
* **Thông tin viện phí:** Bảng biểu phí (Cập nhật thường xuyên bởi Kế toán).
|
||||
* **Hỏi Bác sĩ S.I.S:** Cung cấp Form thu thập câu hỏi gồm các trường:
|
||||
* *Họ tên, SĐT, Email.*
|
||||
* *Chủ đề dropdown:* Thần kinh-Đột quỵ, Tim mạch, Cơ xương khớp, Phục hồi chức năng, Khác.
|
||||
* *Ô nhập Câu hỏi.*
|
||||
|
||||
### VI. GÓC TRUYỀN THÔNG
|
||||
Cho phép khách hàng để lại bình luận/phản hồi ở mọi bài viết.
|
||||
* **Tin tức:** Blog tin bài cập nhật hàng tuần.
|
||||
* **Cẩm nang sức khỏe:** Các lời khuyên của bác sĩ (Đột quỵ, Tim mạch, Cơ xương khớp...).
|
||||
* **Câu chuyện bệnh nhân:** Bài viết hoặc Video thực tế.
|
||||
* **Góc Tri ân:** Nơi đăng tải thư cảm ơn của bệnh nhân.
|
||||
|
||||
### VII. KHÁC
|
||||
* Hoạt động từ thiện / Hoạt động nội bộ
|
||||
* Chương trình Đào tạo / Tuyển dụng
|
||||
* Liên hệ
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **Ghi chú cho Developer:**
|
||||
> Dựa trên yêu cầu này, hệ thống cần một CMS linh hoạt (như đã phân tích là WordPress hoặc hệ thống nội bộ). DB Schema cần chú trọng các bảng: `Doctors`, `Specialties`, `Services/Packages`, `News/Blogs`, `Questions`, và `Reviews`. Phân quyền Backend cần tách biệt rõ ràng cho `Team Truyền thông` (quản lý bài viết) và `Team Kế toán` (Quản lý giá dịch vụ/thanh toán).
|
||||
@@ -0,0 +1,55 @@
|
||||
sonar.projectKey = sisvietnamvn
|
||||
sonar.projectName = sisvietnamvn generated by jhipster
|
||||
|
||||
# Typescript tests files must be inside sources and tests, otherwise `INFO: Test execution data ignored for 80 unknown
|
||||
# files, including:` is shown.
|
||||
sonar.sources = src
|
||||
sonar.tests = src
|
||||
sonar.host.url = http://localhost:9001
|
||||
sonar.sourceEncoding = UTF-8
|
||||
|
||||
sonar.test.inclusions = src/test/**/*.*
|
||||
sonar.junit.reportPaths = build/test-results/test,build/test-results/integrationTest
|
||||
sonar.java.codeCoveragePlugin = jacoco
|
||||
sonar.coverage.jacoco.xmlReportPaths = build/reports/jacoco/test/jacocoTestReport.xml
|
||||
|
||||
sonar.issue.ignore.multicriteria = S7027-domain, S3437, S7027-dto, UndocumentedApi, S125, S4502, S4684, S5145, S6437, S6437-2, S6418, S1192
|
||||
# Rule https://rules.sonarsource.com/java/RSPEC-7027 is ignored for entities
|
||||
sonar.issue.ignore.multicriteria.S7027-domain.resourceKey = src/main/java/com/sisvietnamvn/web/domain/**/*
|
||||
sonar.issue.ignore.multicriteria.S7027-domain.ruleKey = javaarchitecture:S7027
|
||||
# Rule https://rules.sonarsource.com/java/RSPEC-3437 is ignored
|
||||
sonar.issue.ignore.multicriteria.S3437.resourceKey = src/main/java/com/sisvietnamvn/web/**/*
|
||||
sonar.issue.ignore.multicriteria.S3437.ruleKey = squid:S3437
|
||||
# Rule https://rules.sonarsource.com/java/RSPEC-7027 is ignored for dtos
|
||||
sonar.issue.ignore.multicriteria.S7027-dto.resourceKey = src/main/java/com/sisvietnamvn/web/service/dto/**/*
|
||||
sonar.issue.ignore.multicriteria.S7027-dto.ruleKey = javaarchitecture:S7027
|
||||
# Rule https://rules.sonarsource.com/java/RSPEC-1176 is ignored, as we want to follow "clean code" guidelines and
|
||||
# classes, methods and arguments names should be self-explanatory
|
||||
sonar.issue.ignore.multicriteria.UndocumentedApi.resourceKey = src/main/java/com/sisvietnamvn/web/**/*
|
||||
sonar.issue.ignore.multicriteria.UndocumentedApi.ruleKey = squid:UndocumentedApi
|
||||
# Rule https://rules.sonarsource.com/xml/RSPEC-125 is ignored, we provide commented examples
|
||||
sonar.issue.ignore.multicriteria.S125.resourceKey = src/main/resources/logback-spring.xml
|
||||
sonar.issue.ignore.multicriteria.S125.ruleKey = xml:S125
|
||||
# Rule https://rules.sonarsource.com/java/RSPEC-4502 is ignored, as for JWT tokens we are not subject to CSRF attack
|
||||
sonar.issue.ignore.multicriteria.S4502.resourceKey = src/main/java/com/sisvietnamvn/web/config/SecurityConfiguration.java
|
||||
sonar.issue.ignore.multicriteria.S4502.ruleKey = java:S4502
|
||||
# Rule https://rules.sonarsource.com/java/RSPEC-4684
|
||||
sonar.issue.ignore.multicriteria.S4684.resourceKey = src/main/java/com/sisvietnamvn/web/web/rest/**/*
|
||||
sonar.issue.ignore.multicriteria.S4684.ruleKey = java:S4684
|
||||
# Rule https://rules.sonarsource.com/java/RSPEC-5145 is ignored, as we use log filter to format log messages
|
||||
sonar.issue.ignore.multicriteria.S5145.resourceKey = src/main/java/com/sisvietnamvn/web/**/*
|
||||
sonar.issue.ignore.multicriteria.S5145.ruleKey = javasecurity:S5145
|
||||
# Rule https://rules.sonarsource.com/java/RSPEC-6437 is ignored, hardcoded passwords are provided for development
|
||||
# purposes
|
||||
sonar.issue.ignore.multicriteria.S6437.resourceKey = src/main/resources/config/application-secret-samples.yml
|
||||
sonar.issue.ignore.multicriteria.S6437.ruleKey = java:S6437
|
||||
# Rule https://rules.sonarsource.com/java/RSPEC-6437 is ignored, hardcoded passwords are provided for development
|
||||
# purposes
|
||||
sonar.issue.ignore.multicriteria.S6437-2.resourceKey = src/main/resources/config/application-tls.yml
|
||||
sonar.issue.ignore.multicriteria.S6437-2.ruleKey = java:S6437
|
||||
# Rule yaml:S6418 is ignored, hardcoded passwords are provided for development and testing purposes
|
||||
sonar.issue.ignore.multicriteria.S6418.resourceKey = src/main/resources/config/application-secret-samples.yml
|
||||
sonar.issue.ignore.multicriteria.S6418.ruleKey = yaml:S6418
|
||||
# Rule https://rules.sonarsource.com/java/RSPEC-1192, there is no easy way to avoid this issue
|
||||
sonar.issue.ignore.multicriteria.S1192.resourceKey = src/main/java/com/sisvietnamvn/web/config/CacheConfiguration.java
|
||||
sonar.issue.ignore.multicriteria.S1192.ruleKey = java:S1192
|
||||
@@ -0,0 +1,26 @@
|
||||
# This configuration is intended for development purpose, it's **your** responsibility to harden it for production
|
||||
name: sisvietnamvn
|
||||
services:
|
||||
app:
|
||||
image: sisvietnamvn
|
||||
environment:
|
||||
- _JAVA_OPTIONS=-Xmx512m -Xms256m
|
||||
- SPRING_PROFILES_ACTIVE=prod,api-docs,secret-samples
|
||||
- MANAGEMENT_PROMETHEUS_METRICS_EXPORT_ENABLED=true
|
||||
- SPRING_DATASOURCE_URL=jdbc:oracle:thin:@oracle:1521:sisvietnamvn
|
||||
- SPRING_DATASOURCE_USERNAME=system
|
||||
- SPRING_DATASOURCE_PASSWORD=oracle
|
||||
- SPRING_LIQUIBASE_URL=jdbc:oracle:thin:@oracle:1521:sisvietnamvn
|
||||
# If you want to expose these ports outside your dev PC,
|
||||
# remove the "127.0.0.1:" prefix
|
||||
ports:
|
||||
- 127.0.0.1:8080:8080
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
'CMD-SHELL',
|
||||
'bash -c ''exec 3<>/dev/tcp/127.0.0.1/8080; printf "GET /management/health HTTP/1.0\r\nHost: localhost\r\n\r\n" >&3; grep -q "\"status\":\"UP\"" <&3''',
|
||||
]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 40
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
apiVersion: 1
|
||||
|
||||
providers:
|
||||
- name: 'Prometheus'
|
||||
orgId: 1
|
||||
folder: ''
|
||||
type: file
|
||||
disableDeletion: false
|
||||
editable: true
|
||||
options:
|
||||
path: /etc/grafana/provisioning/dashboards
|
||||
@@ -0,0 +1,50 @@
|
||||
apiVersion: 1
|
||||
|
||||
# list of datasources that should be deleted from the database
|
||||
deleteDatasources:
|
||||
- name: Prometheus
|
||||
orgId: 1
|
||||
|
||||
# list of datasources to insert/update depending
|
||||
# whats available in the database
|
||||
datasources:
|
||||
# <string, required> name of the datasource. Required
|
||||
- name: Prometheus
|
||||
# <string, required> datasource type. Required
|
||||
type: prometheus
|
||||
# <string, required> access mode. direct or proxy. Required
|
||||
access: proxy
|
||||
# <int> org id. will default to orgId 1 if not specified
|
||||
orgId: 1
|
||||
# <string> url
|
||||
# On MacOS, replace localhost by host.docker.internal
|
||||
url: http://localhost:9090
|
||||
# <string> database password, if used
|
||||
password:
|
||||
# <string> database user, if used
|
||||
user:
|
||||
# <string> database name, if used
|
||||
database:
|
||||
# <bool> enable/disable basic auth
|
||||
basicAuth: false
|
||||
# <string> basic auth username
|
||||
basicAuthUser: admin
|
||||
# <string> basic auth password
|
||||
basicAuthPassword: admin
|
||||
# <bool> enable/disable with credentials headers
|
||||
withCredentials:
|
||||
# <bool> mark as default datasource. Max one per org
|
||||
isDefault: true
|
||||
# <map> fields that will be converted to json and stored in json_data
|
||||
jsonData:
|
||||
graphiteVersion: '1.1'
|
||||
tlsAuth: false
|
||||
tlsAuthWithCACert: false
|
||||
# <string> json object of data that will be encrypted.
|
||||
secureJsonData:
|
||||
tlsCACert: '...'
|
||||
tlsClientCert: '...'
|
||||
tlsClientKey: '...'
|
||||
version: 1
|
||||
# <bool> allow users to edit datasources from the UI.
|
||||
editable: true
|
||||
@@ -0,0 +1,51 @@
|
||||
## How to use JHCC docker compose
|
||||
# To allow JHCC to reach JHipster application from a docker container note that we set the host as host.docker.internal
|
||||
# To reach the application from a browser, you need to add '127.0.0.1 host.docker.internal' to your hosts file.
|
||||
### Discovery mode
|
||||
# JHCC supports 3 kinds of discovery mode: Consul, Eureka and static
|
||||
# In order to use one, please set SPRING_PROFILES_ACTIVE to one (and only one) of this values: consul,eureka,static
|
||||
### Discovery properties
|
||||
# According to the discovery mode choose as Spring profile, you have to set the right properties
|
||||
# please note that current properties are set to run JHCC with default values, personalize them if needed
|
||||
# and remove those from other modes. You can only have one mode active.
|
||||
#### Eureka
|
||||
# - EUREKA_CLIENT_SERVICE_URL_DEFAULTZONE=http://admin:admin@host.docker.internal:8761/eureka/
|
||||
#### Consul
|
||||
# - SPRING_CLOUD_CONSUL_HOST=host.docker.internal
|
||||
# - SPRING_CLOUD_CONSUL_PORT=8500
|
||||
#### Static
|
||||
# Add instances to "MyApp"
|
||||
# - SPRING_CLOUD_DISCOVERY_CLIENT_SIMPLE_INSTANCES_MYAPP_0_URI=http://host.docker.internal:8081
|
||||
# - SPRING_CLOUD_DISCOVERY_CLIENT_SIMPLE_INSTANCES_MYAPP_1_URI=http://host.docker.internal:8082
|
||||
# Or add a new application named MyNewApp
|
||||
# - SPRING_CLOUD_DISCOVERY_CLIENT_SIMPLE_INSTANCES_MYNEWAPP_0_URI=http://host.docker.internal:8080
|
||||
# This configuration is intended for development purpose, it's **your** responsibility to harden it for production
|
||||
|
||||
#### IMPORTANT
|
||||
# If you choose Consul or Eureka mode:
|
||||
# Do not forget to remove the prefix "127.0.0.1" in front of their port in order to expose them.
|
||||
# This is required because JHCC needs to communicate with Consul or Eureka.
|
||||
# - In Consul mode, the ports are in the consul.yml file.
|
||||
# - In Eureka mode, the ports are in the jhipster-registry.yml file.
|
||||
|
||||
name: sisvietnamvn
|
||||
services:
|
||||
jhipster-control-center:
|
||||
image: 'jhipster/jhipster-control-center:v0.5.0'
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
# Patch /etc/hosts to support resolving host.docker.internal to the internal IP address used by the host in all OSes
|
||||
- echo "`ip route | grep default | cut -d ' ' -f3` host.docker.internal" | tee -a /etc/hosts > /dev/null && java -jar /jhipster-control-center.jar
|
||||
environment:
|
||||
- _JAVA_OPTIONS=-Xmx512m -Xms256m
|
||||
- SPRING_PROFILES_ACTIVE=prod,api-docs,static
|
||||
- SPRING_SECURITY_USER_PASSWORD=admin
|
||||
# The token should have the same value than the one declared in you Spring configuration under the jhipster.security.authentication.jwt.base64-secret configuration's entry
|
||||
- JHIPSTER_SECURITY_AUTHENTICATION_JWT_BASE64_SECRET=ZWRjOTBhYjJiYzg5N2JhMTUyMTBiYzZhNzJjMWUwNmYzOTM3MjJmZGE3Zjc3NGE0ODhjMDZlYzRjNmFiODFhMDNkNmFjNmYwYzY4NmMwNGRkMDMwY2Q0NTllNDlhYzEyMjg0NmY2NzM5MWM1M2IxOTdkMDNhZTBhZDkzYWJjMWI=
|
||||
- SPRING_CLOUD_DISCOVERY_CLIENT_SIMPLE_INSTANCES_SISVIETNAMVN_0_URI=http://host.docker.internal:8080
|
||||
- LOGGING_FILE_NAME=/tmp/jhipster-control-center.log
|
||||
# If you want to expose these ports outside your dev PC,
|
||||
# remove the "127.0.0.1:" prefix
|
||||
ports:
|
||||
- 127.0.0.1:7419:7419
|
||||
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "The application will start in ${JHIPSTER_SLEEP}s..." && sleep ${JHIPSTER_SLEEP}
|
||||
|
||||
# usage: file_env VAR [DEFAULT]
|
||||
# ie: file_env 'XYZ_DB_PASSWORD' 'example'
|
||||
# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
|
||||
# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
|
||||
file_env() {
|
||||
local var="$1"
|
||||
local file_var="${var}_FILE"
|
||||
local def="${2:-}"
|
||||
if [[ ${!var:-} && ${!file_var:-} ]]; then
|
||||
echo >&2 "error: both $var and $file_var are set (but are exclusive)"
|
||||
exit 1
|
||||
fi
|
||||
local val="$def"
|
||||
if [[ ${!var:-} ]]; then
|
||||
val="${!var}"
|
||||
elif [[ ${!file_var:-} ]]; then
|
||||
val="$(< "${!file_var}")"
|
||||
fi
|
||||
|
||||
if [[ -n $val ]]; then
|
||||
export "$var"="$val"
|
||||
fi
|
||||
|
||||
unset "$file_var"
|
||||
return 0
|
||||
}
|
||||
|
||||
file_env 'SPRING_DATASOURCE_URL'
|
||||
file_env 'SPRING_DATASOURCE_USERNAME'
|
||||
file_env 'SPRING_DATASOURCE_PASSWORD'
|
||||
file_env 'SPRING_LIQUIBASE_URL'
|
||||
file_env 'SPRING_LIQUIBASE_USER'
|
||||
file_env 'SPRING_LIQUIBASE_PASSWORD'
|
||||
file_env 'JHIPSTER_REGISTRY_PASSWORD'
|
||||
|
||||
exec java ${JAVA_OPTS} -noverify -XX:+AlwaysPreTouch -cp /app/resources/:/app/classes/:/app/libs/* "com.sisvietnamvn.web.SisvietnamvnApp" "$@"
|
||||
@@ -0,0 +1,31 @@
|
||||
# This configuration is intended for development purpose, it's **your** responsibility to harden it for production
|
||||
name: sisvietnamvn
|
||||
services:
|
||||
prometheus:
|
||||
image: prom/prometheus:v3.11.3
|
||||
volumes:
|
||||
- ./prometheus/:/etc/prometheus/
|
||||
command:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
# If you want to expose these ports outside your dev PC,
|
||||
# remove the "127.0.0.1:" prefix
|
||||
ports:
|
||||
- 127.0.0.1:9090:9090
|
||||
# On MacOS, remove next line and replace localhost by host.docker.internal in prometheus/prometheus.yml and
|
||||
# grafana/provisioning/datasources/datasource.yml
|
||||
network_mode: 'host' # to test locally running service
|
||||
grafana:
|
||||
image: grafana/grafana:13.0.1
|
||||
volumes:
|
||||
- ./grafana/provisioning/:/etc/grafana/provisioning/
|
||||
environment:
|
||||
- GF_SECURITY_ADMIN_PASSWORD=admin
|
||||
- GF_USERS_ALLOW_SIGN_UP=false
|
||||
- GF_INSTALL_PLUGINS=grafana-piechart-panel
|
||||
# If you want to expose these ports outside your dev PC,
|
||||
# remove the "127.0.0.1:" prefix
|
||||
ports:
|
||||
- 127.0.0.1:3000:3000
|
||||
# On MacOS, remove next line and replace localhost by host.docker.internal in prometheus/prometheus.yml and
|
||||
# grafana/provisioning/datasources/datasource.yml
|
||||
network_mode: 'host' # to test locally running service
|
||||
@@ -0,0 +1,18 @@
|
||||
# This configuration is intended for development purpose, it's **your** responsibility to harden it for production
|
||||
name: sisvietnam-oracle
|
||||
services:
|
||||
sisvietnam-oracle:
|
||||
image: gvenzl/oracle-free:23-slim-faststart
|
||||
environment:
|
||||
# Password for the SYS and SYSTEM admin accounts
|
||||
- ORACLE_PASSWORD=Oracle123!
|
||||
# Name of the pluggable database
|
||||
- ORACLE_DATABASE=sisvietnam
|
||||
# Create an app user and password automatically
|
||||
- APP_USER=sisvietnam
|
||||
- APP_USER_PASSWORD=sisvietnam
|
||||
ports:
|
||||
- "1521:1521"
|
||||
# Uncomment the following lines to make the database data persistent across restarts
|
||||
# volumes:
|
||||
# - ~/oracle-data:/opt/oracle/oradata
|
||||
@@ -0,0 +1,31 @@
|
||||
# Sample global config for monitoring JHipster applications
|
||||
global:
|
||||
scrape_interval: 15s # By default, scrape targets every 15 seconds.
|
||||
evaluation_interval: 15s # By default, scrape targets every 15 seconds.
|
||||
# scrape_timeout is set to the global default (10s).
|
||||
|
||||
# Attach these labels to any time series or alerts when communicating with
|
||||
# external systems (federation, remote storage, Alertmanager).
|
||||
external_labels:
|
||||
monitor: 'jhipster'
|
||||
|
||||
# A scrape configuration containing exactly one endpoint to scrape:
|
||||
# Here it's Prometheus itself.
|
||||
scrape_configs:
|
||||
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
|
||||
- job_name: 'prometheus'
|
||||
|
||||
# Override the global default and scrape targets from this job every 5 seconds.
|
||||
scrape_interval: 5s
|
||||
|
||||
# scheme defaults to 'http' enable https in case your application is server via https
|
||||
#scheme: https
|
||||
# basic auth is not needed by default. See https://www.jhipster.tech/monitoring/#configuring-metrics-forwarding for details
|
||||
#basic_auth:
|
||||
# username: admin
|
||||
# password: admin
|
||||
metrics_path: /management/prometheus
|
||||
static_configs:
|
||||
- targets:
|
||||
# On MacOS, replace localhost by host.docker.internal
|
||||
- localhost:8080
|
||||
@@ -0,0 +1,15 @@
|
||||
# This configuration is intended for development purpose, it's **your** responsibility to harden it for production
|
||||
name: sisvietnamvn
|
||||
services:
|
||||
sonar:
|
||||
container_name: sonarqube
|
||||
image: sonarqube:26.5.0.122743-community
|
||||
# Forced authentication redirect for UI is turned off for out of the box experience while trying out SonarQube
|
||||
# For real use cases delete SONAR_FORCEAUTHENTICATION variable or set SONAR_FORCEAUTHENTICATION=true
|
||||
environment:
|
||||
- SONAR_FORCEAUTHENTICATION=false
|
||||
# If you want to expose these ports outside your dev PC,
|
||||
# remove the "127.0.0.1:" prefix
|
||||
ports:
|
||||
- 127.0.0.1:9001:9000
|
||||
- 127.0.0.1:9000:9000
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.sisvietnamvn.web;
|
||||
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
import tech.jhipster.config.DefaultProfileUtil;
|
||||
|
||||
/**
|
||||
* This is a helper Java class that provides an alternative to creating a {@code web.xml}.
|
||||
* This will be invoked only when the application is deployed to a Servlet container like Tomcat, JBoss etc.
|
||||
*/
|
||||
public class ApplicationWebXml extends SpringBootServletInitializer {
|
||||
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
||||
// set a default to use when no profile is configured.
|
||||
DefaultProfileUtil.addDefaultProfile(application.application());
|
||||
return application.sources(SisvietnamvnApp.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.sisvietnamvn.web;
|
||||
|
||||
import jakarta.annotation.Generated;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Generated(value = "JHipster", comments = "Generated by JHipster 9.1.0")
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target({ ElementType.TYPE })
|
||||
public @interface GeneratedByJHipster {}
|
||||
@@ -0,0 +1,111 @@
|
||||
package com.sisvietnamvn.web;
|
||||
|
||||
import com.sisvietnamvn.web.config.ApplicationProperties;
|
||||
import com.sisvietnamvn.web.config.CRLFLogConverter;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.h2console.autoconfigure.H2ConsoleAutoConfiguration;
|
||||
import org.springframework.boot.liquibase.autoconfigure.LiquibaseProperties;
|
||||
import org.springframework.core.env.Environment;
|
||||
import tech.jhipster.config.DefaultProfileUtil;
|
||||
import tech.jhipster.config.JHipsterConstants;
|
||||
|
||||
@SpringBootApplication(exclude = { H2ConsoleAutoConfiguration.class })
|
||||
@EnableConfigurationProperties({ LiquibaseProperties.class, ApplicationProperties.class })
|
||||
public class SisvietnamvnApp {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SisvietnamvnApp.class);
|
||||
|
||||
private final Environment env;
|
||||
|
||||
public SisvietnamvnApp(Environment env) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes sisvietnamvn.
|
||||
* <p>
|
||||
* Spring profiles can be configured with a program argument --spring.profiles.active=your-active-profile
|
||||
* <p>
|
||||
* You can find more information on how profiles work with JHipster on <a href="https://www.jhipster.tech/profiles/">https://www.jhipster.tech/profiles/</a>.
|
||||
*/
|
||||
@PostConstruct
|
||||
public void initApplication() {
|
||||
Collection<String> activeProfiles = List.of(env.getActiveProfiles());
|
||||
if (
|
||||
activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) &&
|
||||
activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_PRODUCTION)
|
||||
) {
|
||||
LOG.error(
|
||||
"You have misconfigured your application! It should not run " + "with both the 'dev' and 'prod' profiles at the same time."
|
||||
);
|
||||
}
|
||||
if (
|
||||
activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) &&
|
||||
activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_CLOUD)
|
||||
) {
|
||||
LOG.error(
|
||||
"You have misconfigured your application! It should not " + "run with both the 'dev' and 'cloud' profiles at the same time."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main method, used to run the application.
|
||||
*
|
||||
* @param args the command line arguments.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
var app = new SpringApplication(SisvietnamvnApp.class);
|
||||
DefaultProfileUtil.addDefaultProfile(app);
|
||||
Environment env = app.run(args).getEnvironment();
|
||||
logApplicationStartup(env);
|
||||
}
|
||||
|
||||
private static void logApplicationStartup(Environment env) {
|
||||
String protocol = Optional.ofNullable(env.getProperty("server.ssl.key-store"))
|
||||
.map(key -> "https")
|
||||
.orElse("http");
|
||||
String applicationName = env.getProperty("spring.application.name");
|
||||
String serverPort = env.getProperty("server.port");
|
||||
String contextPath = Optional.ofNullable(env.getProperty("server.servlet.context-path"))
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.orElse("/");
|
||||
var hostAddress = "localhost";
|
||||
try {
|
||||
hostAddress = InetAddress.getLocalHost().getHostAddress();
|
||||
} catch (UnknownHostException e) {
|
||||
LOG.warn("The host name could not be determined, using `localhost` as fallback");
|
||||
}
|
||||
LOG.info(
|
||||
CRLFLogConverter.CRLF_SAFE_MARKER,
|
||||
"""
|
||||
|
||||
----------------------------------------------------------
|
||||
\tApplication '{}' is running! Access URLs:
|
||||
\tLocal: \t\t{}://localhost:{}{}
|
||||
\tExternal: \t{}://{}:{}{}
|
||||
\tProfile(s): \t{}
|
||||
----------------------------------------------------------""",
|
||||
applicationName,
|
||||
protocol,
|
||||
serverPort,
|
||||
contextPath,
|
||||
protocol,
|
||||
hostAddress,
|
||||
serverPort,
|
||||
contextPath,
|
||||
env.getActiveProfiles().length == 0 ? env.getDefaultProfiles() : env.getActiveProfiles()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.sisvietnamvn.web;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SisvietnamvnApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SisvietnamvnApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package com.sisvietnamvn.web.aop.logging;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.AfterThrowing;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.Profiles;
|
||||
import tech.jhipster.config.JHipsterConstants;
|
||||
|
||||
/**
|
||||
* Aspect for logging execution of service and repository Spring components.
|
||||
*
|
||||
* By default, it only runs with the "dev" profile.
|
||||
*/
|
||||
@Aspect
|
||||
public class LoggingAspect {
|
||||
|
||||
private final Environment env;
|
||||
|
||||
public LoggingAspect(Environment env) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pointcut that matches all repositories, services and Web REST endpoints.
|
||||
*/
|
||||
@Pointcut(
|
||||
"""
|
||||
within(@org.springframework.stereotype.Repository *)
|
||||
|| within(@org.springframework.stereotype.Service *)
|
||||
|| within(@org.springframework.web.bind.annotation.RestController *)
|
||||
"""
|
||||
)
|
||||
public void springBeanPointcut() {
|
||||
// Method is empty as this is just a Pointcut, the implementations are in the advices.
|
||||
}
|
||||
|
||||
/**
|
||||
* Pointcut that matches all Spring beans in the application's main packages.
|
||||
*/
|
||||
@Pointcut(
|
||||
"""
|
||||
within(com.sisvietnamvn.web.repository..*)
|
||||
|| within(com.sisvietnamvn.web.service..*)
|
||||
|| within(com.sisvietnamvn.web.web.rest..*)
|
||||
"""
|
||||
)
|
||||
public void applicationPackagePointcut() {
|
||||
// Method is empty as this is just a Pointcut, the implementations are in the advices.
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the {@link Logger} associated to the given {@link JoinPoint}.
|
||||
*
|
||||
* @param joinPoint join point we want the logger for.
|
||||
* @return {@link Logger} associated to the given {@link JoinPoint}.
|
||||
*/
|
||||
private Logger logger(JoinPoint joinPoint) {
|
||||
return LoggerFactory.getLogger(joinPoint.getSignature().getDeclaringTypeName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Advice that logs methods throwing exceptions.
|
||||
*
|
||||
* @param joinPoint join point for advice.
|
||||
* @param e exception.
|
||||
*/
|
||||
@AfterThrowing(pointcut = "applicationPackagePointcut() && springBeanPointcut()", throwing = "e")
|
||||
public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
|
||||
if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT))) {
|
||||
logger(joinPoint).error(
|
||||
"Exception in {}() with cause = '{}' and exception = '{}'",
|
||||
joinPoint.getSignature().getName(),
|
||||
e.getCause() != null ? e.getCause() : "NULL",
|
||||
e.getMessage(),
|
||||
e
|
||||
);
|
||||
} else {
|
||||
logger(joinPoint).error(
|
||||
"Exception in {}() with cause = {}",
|
||||
joinPoint.getSignature().getName(),
|
||||
e.getCause() != null ? String.valueOf(e.getCause()) : "NULL"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Advice that logs when a method is entered and exited.
|
||||
*
|
||||
* @param joinPoint join point for advice.
|
||||
* @return result.
|
||||
* @throws Throwable throws {@link IllegalArgumentException}.
|
||||
*/
|
||||
@Around("applicationPackagePointcut() && springBeanPointcut()")
|
||||
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
var log = logger(joinPoint);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Enter: {}() with argument[s] = {}", joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs()));
|
||||
}
|
||||
try {
|
||||
Object result = joinPoint.proceed();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Exit: {}() with result = {}", joinPoint.getSignature().getName(), result);
|
||||
}
|
||||
return result;
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.error("Illegal argument: {} in {}()", Arrays.toString(joinPoint.getArgs()), joinPoint.getSignature().getName());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Logging aspect.
|
||||
*/
|
||||
package com.sisvietnamvn.web.aop.logging;
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.sisvietnamvn.web.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Properties specific to Sisvietnamvn.
|
||||
* <p>
|
||||
* Properties are configured in the {@code application.yml} file.
|
||||
* See {@link tech.jhipster.config.JHipsterProperties} for a good example.
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "application", ignoreUnknownFields = false)
|
||||
public class ApplicationProperties {
|
||||
|
||||
private final Liquibase liquibase = new Liquibase();
|
||||
|
||||
// jhipster-needle-application-properties-property
|
||||
|
||||
public Liquibase getLiquibase() {
|
||||
return liquibase;
|
||||
}
|
||||
|
||||
// jhipster-needle-application-properties-property-getter
|
||||
|
||||
public static class Liquibase {
|
||||
|
||||
private Boolean asyncStart = true;
|
||||
|
||||
public Boolean getAsyncStart() {
|
||||
return asyncStart;
|
||||
}
|
||||
|
||||
public void setAsyncStart(Boolean asyncStart) {
|
||||
this.asyncStart = asyncStart;
|
||||
}
|
||||
}
|
||||
|
||||
// jhipster-needle-application-properties-property-class
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.sisvietnamvn.web.config;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
|
||||
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
|
||||
import org.springframework.boot.autoconfigure.task.TaskExecutionProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.scheduling.annotation.AsyncConfigurer;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import tech.jhipster.async.ExceptionHandlingAsyncTaskExecutor;
|
||||
|
||||
@Configuration
|
||||
@EnableAsync
|
||||
@EnableScheduling
|
||||
@Profile("!testdev & !testprod")
|
||||
public class AsyncConfiguration implements AsyncConfigurer {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AsyncConfiguration.class);
|
||||
|
||||
private final TaskExecutionProperties taskExecutionProperties;
|
||||
|
||||
public AsyncConfiguration(TaskExecutionProperties taskExecutionProperties) {
|
||||
this.taskExecutionProperties = taskExecutionProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Bean(name = "taskExecutor")
|
||||
public Executor getAsyncExecutor() {
|
||||
LOG.debug("Creating Async Task Executor");
|
||||
var executor = new ThreadPoolTaskExecutor();
|
||||
executor.setCorePoolSize(taskExecutionProperties.getPool().getCoreSize());
|
||||
executor.setMaxPoolSize(taskExecutionProperties.getPool().getMaxSize());
|
||||
executor.setQueueCapacity(taskExecutionProperties.getPool().getQueueCapacity());
|
||||
executor.setThreadNamePrefix(taskExecutionProperties.getThreadNamePrefix());
|
||||
return new ExceptionHandlingAsyncTaskExecutor(executor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
|
||||
return new SimpleAsyncUncaughtExceptionHandler();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.sisvietnamvn.web.config;
|
||||
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.pattern.CompositeConverter;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.slf4j.Marker;
|
||||
import org.slf4j.MarkerFactory;
|
||||
import org.springframework.boot.ansi.AnsiColor;
|
||||
import org.springframework.boot.ansi.AnsiElement;
|
||||
import org.springframework.boot.ansi.AnsiOutput;
|
||||
import org.springframework.boot.ansi.AnsiStyle;
|
||||
|
||||
/**
|
||||
* Log filter to prevent attackers from forging log entries by submitting input containing CRLF characters.
|
||||
* CRLF characters are replaced with a red colored _ character.
|
||||
*
|
||||
* @see <a href="https://owasp.org/www-community/attacks/Log_Injection">Log Forging Description</a>
|
||||
* @see <a href="https://github.com/jhipster/generator-jhipster/issues/14949">JHipster issue</a>
|
||||
*/
|
||||
public class CRLFLogConverter extends CompositeConverter<ILoggingEvent> {
|
||||
|
||||
public static final Marker CRLF_SAFE_MARKER = MarkerFactory.getMarker("CRLF_SAFE");
|
||||
|
||||
private static final String[] SAFE_LOGS = {
|
||||
"org.hibernate",
|
||||
"org.springframework.boot.autoconfigure",
|
||||
"org.springframework.boot.diagnostics",
|
||||
};
|
||||
private static final Map<String, AnsiElement> ELEMENTS;
|
||||
|
||||
static {
|
||||
Map<String, AnsiElement> ansiElements = new HashMap<>();
|
||||
ansiElements.put("faint", AnsiStyle.FAINT);
|
||||
ansiElements.put("red", AnsiColor.RED);
|
||||
ansiElements.put("green", AnsiColor.GREEN);
|
||||
ansiElements.put("yellow", AnsiColor.YELLOW);
|
||||
ansiElements.put("blue", AnsiColor.BLUE);
|
||||
ansiElements.put("magenta", AnsiColor.MAGENTA);
|
||||
ansiElements.put("cyan", AnsiColor.CYAN);
|
||||
ELEMENTS = Collections.unmodifiableMap(ansiElements);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String transform(ILoggingEvent event, String in) {
|
||||
AnsiElement element = ELEMENTS.get(getFirstOption());
|
||||
List<Marker> markers = event.getMarkerList();
|
||||
if ((markers != null && !markers.isEmpty() && markers.getFirst().contains(CRLF_SAFE_MARKER)) || isLoggerSafe(event)) {
|
||||
return in;
|
||||
}
|
||||
String replacement = element == null ? "_" : toAnsiString("_", element);
|
||||
return in.replaceAll("[\n\r\t]", replacement);
|
||||
}
|
||||
|
||||
protected boolean isLoggerSafe(ILoggingEvent event) {
|
||||
for (String safeLogger : SAFE_LOGS) {
|
||||
if (event.getLoggerName().startsWith(safeLogger)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected String toAnsiString(String in, AnsiElement element) {
|
||||
return AnsiOutput.toString(element, in);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.sisvietnamvn.web.config;
|
||||
|
||||
import java.time.Duration;
|
||||
import org.ehcache.config.builders.*;
|
||||
import org.ehcache.jsr107.Eh107Configuration;
|
||||
import org.hibernate.cache.jcache.ConfigSettings;
|
||||
import org.springframework.boot.cache.autoconfigure.JCacheManagerCustomizer;
|
||||
import org.springframework.boot.hibernate.autoconfigure.HibernatePropertiesCustomizer;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import tech.jhipster.config.JHipsterProperties;
|
||||
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
public class CacheConfiguration {
|
||||
|
||||
private final javax.cache.configuration.Configuration<Object, Object> jcacheConfiguration;
|
||||
|
||||
public CacheConfiguration(JHipsterProperties jHipsterProperties) {
|
||||
var ehcache = jHipsterProperties.getCache().getEhcache();
|
||||
|
||||
jcacheConfiguration = Eh107Configuration.fromEhcacheCacheConfiguration(
|
||||
CacheConfigurationBuilder.newCacheConfigurationBuilder(
|
||||
Object.class,
|
||||
Object.class,
|
||||
ResourcePoolsBuilder.heap(ehcache.getMaxEntries())
|
||||
)
|
||||
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(ehcache.getTimeToLiveSeconds())))
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HibernatePropertiesCustomizer hibernatePropertiesCustomizer(javax.cache.CacheManager cacheManager) {
|
||||
return hibernateProperties -> hibernateProperties.put(ConfigSettings.CACHE_MANAGER, cacheManager);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JCacheManagerCustomizer cacheManagerCustomizer() {
|
||||
return cm -> {
|
||||
createCache(cm, com.sisvietnamvn.web.repository.UserRepository.USERS_BY_LOGIN_CACHE);
|
||||
createCache(cm, com.sisvietnamvn.web.repository.UserRepository.USERS_BY_EMAIL_CACHE);
|
||||
createCache(cm, com.sisvietnamvn.web.domain.User.class.getName());
|
||||
createCache(cm, com.sisvietnamvn.web.domain.Authority.class.getName());
|
||||
createCache(cm, com.sisvietnamvn.web.domain.User.class.getName() + ".authorities");
|
||||
// jhipster-needle-ehcache-add-entry
|
||||
};
|
||||
}
|
||||
|
||||
private void createCache(javax.cache.CacheManager cm, String cacheName) {
|
||||
javax.cache.Cache<Object, Object> cache = cm.getCache(cacheName);
|
||||
if (cache != null) {
|
||||
cache.clear();
|
||||
} else {
|
||||
cm.createCache(cacheName, jcacheConfiguration);
|
||||
}
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.sisvietnamvn.web.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.info.BuildProperties;
|
||||
import org.springframework.boot.info.GitProperties;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import tech.jhipster.config.cache.PrefixedKeyGenerator;
|
||||
|
||||
@Configuration
|
||||
public class CacheKeyGeneratorConfiguration {
|
||||
|
||||
private GitProperties gitProperties;
|
||||
private BuildProperties buildProperties;
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setGitProperties(GitProperties gitProperties) {
|
||||
this.gitProperties = gitProperties;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setBuildProperties(BuildProperties buildProperties) {
|
||||
this.buildProperties = buildProperties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KeyGenerator keyGenerator() {
|
||||
return new PrefixedKeyGenerator(this.gitProperties, this.buildProperties);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.sisvietnamvn.web.config;
|
||||
|
||||
/**
|
||||
* Application constants.
|
||||
*/
|
||||
public final class Constants {
|
||||
|
||||
// Regex for acceptable logins
|
||||
public static final String LOGIN_REGEX = "^(?>[a-zA-Z0-9!$&*+=?^_`{|}~.-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*)|(?>[_.@A-Za-z0-9-]+)$";
|
||||
|
||||
public static final String SYSTEM = "system";
|
||||
public static final String DEFAULT_LANGUAGE = "en";
|
||||
|
||||
private Constants() {}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.sisvietnamvn.web.config;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.h2console.autoconfigure.H2ConsoleProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
import tech.jhipster.config.JHipsterConstants;
|
||||
import tech.jhipster.config.h2.H2ConfigurationHelper;
|
||||
|
||||
@Configuration
|
||||
@EnableJpaRepositories({ "com.sisvietnamvn.web.repository" })
|
||||
@EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware")
|
||||
@EnableTransactionManagement
|
||||
@EnableConfigurationProperties(H2ConsoleProperties.class)
|
||||
public class DatabaseConfiguration {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DatabaseConfiguration.class);
|
||||
|
||||
private final Environment env;
|
||||
|
||||
public DatabaseConfiguration(Environment env) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the TCP port for the H2 database, so it is available remotely.
|
||||
*
|
||||
* @return the H2 database TCP server.
|
||||
* @throws SQLException if the server failed to start.
|
||||
*/
|
||||
@Bean(initMethod = "start", destroyMethod = "stop")
|
||||
@Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)
|
||||
@ConditionalOnProperty(prefix = "spring.h2.console", name = "enabled", havingValue = "true")
|
||||
public Object h2TCPServer() throws SQLException {
|
||||
String port = getValidPortForH2();
|
||||
LOG.debug("H2 database is available on port {}", port);
|
||||
return H2ConfigurationHelper.createServer(port);
|
||||
}
|
||||
|
||||
private String getValidPortForH2() {
|
||||
var port = Integer.parseInt(env.getProperty("server.port"));
|
||||
if (port < 10000) {
|
||||
port = 10000 + port;
|
||||
} else {
|
||||
if (port < 63536) {
|
||||
port = port + 2000;
|
||||
} else {
|
||||
port = port - 2000;
|
||||
}
|
||||
}
|
||||
return String.valueOf(port);
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.sisvietnamvn.web.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* Configure the converters to use the ISO format for dates by default.
|
||||
*/
|
||||
@Configuration
|
||||
public class DateTimeFormatConfiguration implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addFormatters(FormatterRegistry registry) {
|
||||
var registrar = new DateTimeFormatterRegistrar();
|
||||
registrar.setUseIsoFormat(true);
|
||||
registrar.registerFormatters(registry);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.sisvietnamvn.web.config;
|
||||
|
||||
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class JacksonConfiguration {
|
||||
|
||||
/**
|
||||
* Support for Java date and time API.
|
||||
* @return the corresponding Jackson module.
|
||||
*/
|
||||
@Bean
|
||||
public JavaTimeModule javaTimeModule() {
|
||||
return new JavaTimeModule();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Jdk8Module jdk8TimeModule() {
|
||||
return new Jdk8Module();
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.sisvietnamvn.web.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import tools.jackson.datatype.hibernate7.Hibernate7Module;
|
||||
import tools.jackson.datatype.hibernate7.Hibernate7Module.Feature;
|
||||
|
||||
@Configuration
|
||||
public class JacksonHibernateConfiguration {
|
||||
|
||||
/*
|
||||
* Support for Hibernate types in Jackson.
|
||||
*/
|
||||
@Bean
|
||||
public Hibernate7Module hibernate7Module() {
|
||||
return new Hibernate7Module().configure(Feature.SERIALIZE_IDENTIFIER_FOR_LAZY_NOT_LOADED_OBJECTS, true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.sisvietnamvn.web.config;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import javax.sql.DataSource;
|
||||
import liquibase.integration.spring.SpringLiquibase;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties;
|
||||
import org.springframework.boot.liquibase.autoconfigure.LiquibaseDataSource;
|
||||
import org.springframework.boot.liquibase.autoconfigure.LiquibaseProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import tech.jhipster.config.JHipsterConstants;
|
||||
import tech.jhipster.config.liquibase.SpringLiquibaseUtil;
|
||||
|
||||
@Configuration
|
||||
public class LiquibaseConfiguration {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LiquibaseConfiguration.class);
|
||||
|
||||
private final Environment env;
|
||||
|
||||
public LiquibaseConfiguration(Environment env) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SpringLiquibase liquibase(
|
||||
@Qualifier("taskExecutor") Executor executor,
|
||||
LiquibaseProperties liquibaseProperties,
|
||||
@LiquibaseDataSource ObjectProvider<DataSource> liquibaseDataSource,
|
||||
ObjectProvider<DataSource> dataSource,
|
||||
ApplicationProperties applicationProperties,
|
||||
DataSourceProperties dataSourceProperties
|
||||
) {
|
||||
SpringLiquibase liquibase;
|
||||
if (Boolean.TRUE.equals(applicationProperties.getLiquibase().getAsyncStart())) {
|
||||
liquibase = SpringLiquibaseUtil.createAsyncSpringLiquibase(
|
||||
this.env,
|
||||
executor,
|
||||
liquibaseDataSource.getIfAvailable(),
|
||||
liquibaseProperties,
|
||||
dataSource.getIfUnique(),
|
||||
dataSourceProperties
|
||||
);
|
||||
} else {
|
||||
liquibase = SpringLiquibaseUtil.createSpringLiquibase(
|
||||
liquibaseDataSource.getIfAvailable(),
|
||||
liquibaseProperties,
|
||||
dataSource.getIfUnique(),
|
||||
dataSourceProperties
|
||||
);
|
||||
}
|
||||
liquibase.setChangeLog("classpath:config/liquibase/master.xml");
|
||||
if (!CollectionUtils.isEmpty(liquibaseProperties.getContexts())) {
|
||||
liquibase.setContexts(StringUtils.collectionToCommaDelimitedString(liquibaseProperties.getContexts()));
|
||||
}
|
||||
liquibase.setDefaultSchema(liquibaseProperties.getDefaultSchema());
|
||||
liquibase.setLiquibaseSchema(liquibaseProperties.getLiquibaseSchema());
|
||||
liquibase.setLiquibaseTablespace(liquibaseProperties.getLiquibaseTablespace());
|
||||
liquibase.setDatabaseChangeLogLockTable(liquibaseProperties.getDatabaseChangeLogLockTable());
|
||||
liquibase.setDatabaseChangeLogTable(liquibaseProperties.getDatabaseChangeLogTable());
|
||||
liquibase.setDropFirst(liquibaseProperties.isDropFirst());
|
||||
if (!CollectionUtils.isEmpty(liquibaseProperties.getLabelFilter())) {
|
||||
liquibase.setLabelFilter(StringUtils.collectionToCommaDelimitedString(liquibaseProperties.getLabelFilter()));
|
||||
}
|
||||
liquibase.setChangeLogParameters(liquibaseProperties.getParameters());
|
||||
liquibase.setRollbackFile(liquibaseProperties.getRollbackFile());
|
||||
liquibase.setTestRollbackOnUpdate(liquibaseProperties.isTestRollbackOnUpdate());
|
||||
if (env.matchesProfiles(JHipsterConstants.SPRING_PROFILE_NO_LIQUIBASE)) {
|
||||
liquibase.setShouldRun(false);
|
||||
} else {
|
||||
liquibase.setShouldRun(liquibaseProperties.isEnabled());
|
||||
LOG.debug("Configuring Liquibase");
|
||||
}
|
||||
return liquibase;
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.sisvietnamvn.web.config;
|
||||
|
||||
import com.sisvietnamvn.web.aop.logging.LoggingAspect;
|
||||
import org.springframework.context.annotation.*;
|
||||
import org.springframework.core.env.Environment;
|
||||
import tech.jhipster.config.JHipsterConstants;
|
||||
|
||||
@Configuration
|
||||
@EnableAspectJAutoProxy
|
||||
public class LoggingAspectConfiguration {
|
||||
|
||||
@Bean
|
||||
@Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)
|
||||
public LoggingAspect loggingAspect(Environment env) {
|
||||
return new LoggingAspect(env);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.sisvietnamvn.web.config;
|
||||
|
||||
import static tech.jhipster.config.logging.LoggingUtils.*;
|
||||
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import tech.jhipster.config.JHipsterProperties;
|
||||
import tools.jackson.core.JacksonException;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
/*
|
||||
* Configures the console and Logstash log appenders from the app properties
|
||||
*/
|
||||
@Configuration
|
||||
public class LoggingConfiguration {
|
||||
|
||||
public LoggingConfiguration(
|
||||
@Value("${spring.application.name}") String appName,
|
||||
@Value("${server.port}") String serverPort,
|
||||
JHipsterProperties jHipsterProperties,
|
||||
ObjectMapper mapper
|
||||
) throws JacksonException {
|
||||
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("app_name", appName);
|
||||
map.put("app_port", serverPort);
|
||||
var customFields = mapper.writeValueAsString(map);
|
||||
|
||||
var loggingProperties = jHipsterProperties.getLogging();
|
||||
var logstashProperties = loggingProperties.getLogstash();
|
||||
|
||||
if (loggingProperties.isUseJsonFormat()) {
|
||||
addJsonConsoleAppender(context, customFields);
|
||||
}
|
||||
if (logstashProperties.isEnabled()) {
|
||||
addLogstashTcpSocketAppender(context, customFields, logstashProperties);
|
||||
}
|
||||
if (loggingProperties.isUseJsonFormat() || logstashProperties.isEnabled()) {
|
||||
addContextListener(context, customFields, loggingProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.sisvietnamvn.web.config;
|
||||
|
||||
import static org.springframework.security.config.Customizer.withDefaults;
|
||||
|
||||
import com.sisvietnamvn.web.security.*;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.Profiles;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
|
||||
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import tech.jhipster.config.JHipsterConstants;
|
||||
import tech.jhipster.config.JHipsterProperties;
|
||||
|
||||
@Configuration
|
||||
@EnableMethodSecurity(securedEnabled = true)
|
||||
public class SecurityConfiguration {
|
||||
|
||||
private final Environment env;
|
||||
|
||||
private final JHipsterProperties jHipsterProperties;
|
||||
|
||||
public SecurityConfiguration(Environment env, JHipsterProperties jHipsterProperties) {
|
||||
this.env = env;
|
||||
this.jHipsterProperties = jHipsterProperties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) {
|
||||
http.cors(withDefaults())
|
||||
.csrf(csrf -> csrf.disable())
|
||||
.authorizeHttpRequests(authz ->
|
||||
// prettier-ignore
|
||||
authz
|
||||
.requestMatchers(HttpMethod.GET, "/", "/about", "/flex-finish", "/tin-tuc", "/tin-tuc/**", "/lien-he",
|
||||
"/manage/**", "/css/**", "/images/**", "/js/**", "/UMass*/**", "/Undergraduate*/**",
|
||||
"/favicon.ico", "/favicons/**", "/flex-finish/**", "/contact-us/**")
|
||||
.permitAll()
|
||||
.requestMatchers(HttpMethod.GET, "/swagger-ui/**", "/v3/api-docs/**").permitAll()
|
||||
.requestMatchers(HttpMethod.POST, "/api/authenticate").permitAll()
|
||||
.requestMatchers(HttpMethod.GET, "/api/authenticate").permitAll()
|
||||
.requestMatchers("/api/register").permitAll()
|
||||
.requestMatchers("/api/activate").permitAll()
|
||||
.requestMatchers("/api/account/reset-password/init").permitAll()
|
||||
.requestMatchers("/api/account/reset-password/finish").permitAll()
|
||||
.requestMatchers("/api/admin/**").hasAuthority(AuthoritiesConstants.ADMIN)
|
||||
.requestMatchers("/api/**").authenticated()
|
||||
.requestMatchers("/management/health").permitAll()
|
||||
.requestMatchers("/management/health/**").permitAll()
|
||||
.requestMatchers("/management/info").permitAll()
|
||||
.requestMatchers("/management/prometheus").permitAll()
|
||||
.requestMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN))
|
||||
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||
.exceptionHandling(exceptions -> exceptions
|
||||
.authenticationEntryPoint(new BearerTokenAuthenticationEntryPoint())
|
||||
.accessDeniedHandler(new BearerTokenAccessDeniedHandler()))
|
||||
.oauth2ResourceServer(oauth2 -> oauth2.jwt(withDefaults()));
|
||||
if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT))) {
|
||||
http.authorizeHttpRequests(authz -> authz.requestMatchers("/h2-console/**").permitAll())
|
||||
.headers(headers -> headers.frameOptions(frameOptions -> frameOptions.sameOrigin()));
|
||||
}
|
||||
return http.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.sisvietnamvn.web.config;
|
||||
|
||||
import static com.sisvietnamvn.web.security.SecurityUtils.JWT_ALGORITHM;
|
||||
|
||||
import com.nimbusds.jose.jwk.source.ImmutableSecret;
|
||||
import com.nimbusds.jose.util.Base64;
|
||||
import com.sisvietnamvn.web.management.SecurityMetersService;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.JwtEncoder;
|
||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
|
||||
|
||||
@Configuration
|
||||
public class SecurityJwtConfiguration {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SecurityJwtConfiguration.class);
|
||||
|
||||
@Value("${jhipster.security.authentication.jwt.base64-secret}")
|
||||
private String jwtKey;
|
||||
|
||||
@Bean
|
||||
public JwtDecoder jwtDecoder(SecurityMetersService metersService) {
|
||||
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withSecretKey(getSecretKey()).macAlgorithm(JWT_ALGORITHM).build();
|
||||
return token -> {
|
||||
try {
|
||||
return jwtDecoder.decode(token);
|
||||
} catch (Exception e) {
|
||||
if (e.getMessage().contains("Invalid signature")) {
|
||||
metersService.trackTokenInvalidSignature();
|
||||
} else if (e.getMessage().contains("Jwt expired at")) {
|
||||
metersService.trackTokenExpired();
|
||||
} else if (
|
||||
e.getMessage().contains("Invalid JWT serialization") ||
|
||||
e.getMessage().contains("Malformed token") ||
|
||||
e.getMessage().contains("Invalid unsecured/JWS/JWE")
|
||||
) {
|
||||
metersService.trackTokenMalformed();
|
||||
} else {
|
||||
LOG.error("Unknown JWT error {}", e.getMessage());
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JwtEncoder jwtEncoder() {
|
||||
return new NimbusJwtEncoder(new ImmutableSecret<>(getSecretKey()));
|
||||
}
|
||||
|
||||
private SecretKey getSecretKey() {
|
||||
byte[] keyBytes = Base64.from(jwtKey).decode();
|
||||
return new SecretKeySpec(keyBytes, 0, keyBytes.length, JWT_ALGORITHM.getName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.sisvietnamvn.web.config;
|
||||
|
||||
import jakarta.servlet.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.web.server.*;
|
||||
import org.springframework.boot.web.servlet.ServletContextInitializer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.Profiles;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
import tech.jhipster.config.JHipsterConstants;
|
||||
import tech.jhipster.config.JHipsterProperties;
|
||||
import tech.jhipster.config.h2.H2ConfigurationHelper;
|
||||
|
||||
/**
|
||||
* Configuration of web application with Servlet 3.0 APIs.
|
||||
*/
|
||||
@Configuration
|
||||
public class WebConfigurer implements ServletContextInitializer {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(WebConfigurer.class);
|
||||
|
||||
private final Environment env;
|
||||
|
||||
private final JHipsterProperties jHipsterProperties;
|
||||
|
||||
public WebConfigurer(Environment env, JHipsterProperties jHipsterProperties) {
|
||||
this.env = env;
|
||||
this.jHipsterProperties = jHipsterProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartup(ServletContext servletContext) {
|
||||
if (env.getActiveProfiles().length != 0) {
|
||||
LOG.info("Web application configuration, using profiles: {}", (Object[]) env.getActiveProfiles());
|
||||
}
|
||||
|
||||
if (h2ConsoleIsEnabled(env)) {
|
||||
initH2Console(servletContext);
|
||||
}
|
||||
LOG.info("Web application fully configured");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CorsFilter corsFilter() {
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
CorsConfiguration config = jHipsterProperties.getCors();
|
||||
if (!CollectionUtils.isEmpty(config.getAllowedOrigins()) || !CollectionUtils.isEmpty(config.getAllowedOriginPatterns())) {
|
||||
LOG.debug("Registering CORS filter");
|
||||
source.registerCorsConfiguration("/api/**", config);
|
||||
source.registerCorsConfiguration("/management/**", config);
|
||||
source.registerCorsConfiguration("/v3/api-docs", config);
|
||||
source.registerCorsConfiguration("/swagger-ui/**", config);
|
||||
}
|
||||
return new CorsFilter(source);
|
||||
}
|
||||
|
||||
private boolean h2ConsoleIsEnabled(Environment env) {
|
||||
return (
|
||||
env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) &&
|
||||
"true".equals(env.getProperty("spring.h2.console.enabled"))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes H2 console.
|
||||
*/
|
||||
private void initH2Console(ServletContext servletContext) {
|
||||
LOG.info("Initialize H2 console");
|
||||
H2ConfigurationHelper.initH2Console(servletContext);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Application configuration.
|
||||
*/
|
||||
package com.sisvietnamvn.web.config;
|
||||
@@ -22,4 +22,15 @@ public class HomeController {
|
||||
public String about() {
|
||||
return "about";
|
||||
}
|
||||
|
||||
// Trang Tin tức
|
||||
@GetMapping("/tin-tuc")
|
||||
public String tintuc() {
|
||||
return "tin-tuc";
|
||||
}
|
||||
|
||||
@GetMapping("/lien-he")
|
||||
public String lienhe() {
|
||||
return "lien-he";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.sisvietnamvn.web.controller;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/manage")
|
||||
public class ManageController {
|
||||
|
||||
@GetMapping({"", "/"})
|
||||
public String index() {
|
||||
return "manage/index";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.sisvietnamvn.web.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.MappedSuperclass;
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
import org.springframework.data.annotation.CreatedBy;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedBy;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
/**
|
||||
* Base abstract class for entities which will hold definitions for created, last modified, created by,
|
||||
* last modified by attributes.
|
||||
*/
|
||||
@MappedSuperclass
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
@JsonIgnoreProperties(value = { "createdBy", "createdDate", "lastModifiedBy", "lastModifiedDate" }, allowGetters = true)
|
||||
public abstract class AbstractAuditingEntity<T> implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public abstract T getId();
|
||||
|
||||
@CreatedBy
|
||||
@Column(name = "created_by", nullable = false, length = 50, updatable = false)
|
||||
private String createdBy;
|
||||
|
||||
@CreatedDate
|
||||
@Column(name = "created_date", updatable = false)
|
||||
private Instant createdDate = Instant.now();
|
||||
|
||||
@LastModifiedBy
|
||||
@Column(name = "last_modified_by", length = 50)
|
||||
private String lastModifiedBy;
|
||||
|
||||
@LastModifiedDate
|
||||
@Column(name = "last_modified_date")
|
||||
private Instant lastModifiedDate = Instant.now();
|
||||
|
||||
public String getCreatedBy() {
|
||||
return createdBy;
|
||||
}
|
||||
|
||||
public void setCreatedBy(String createdBy) {
|
||||
this.createdBy = createdBy;
|
||||
}
|
||||
|
||||
public Instant getCreatedDate() {
|
||||
return createdDate;
|
||||
}
|
||||
|
||||
public void setCreatedDate(Instant createdDate) {
|
||||
this.createdDate = createdDate;
|
||||
}
|
||||
|
||||
public String getLastModifiedBy() {
|
||||
return lastModifiedBy;
|
||||
}
|
||||
|
||||
public void setLastModifiedBy(String lastModifiedBy) {
|
||||
this.lastModifiedBy = lastModifiedBy;
|
||||
}
|
||||
|
||||
public Instant getLastModifiedDate() {
|
||||
return lastModifiedDate;
|
||||
}
|
||||
|
||||
public void setLastModifiedDate(Instant lastModifiedDate) {
|
||||
this.lastModifiedDate = lastModifiedDate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.sisvietnamvn.web.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.springframework.data.domain.Persistable;
|
||||
|
||||
/**
|
||||
* A Authority.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "jhi_authority")
|
||||
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
|
||||
@JsonIgnoreProperties(value = { "new", "id" })
|
||||
@SuppressWarnings("common-java:DuplicatedBlocks")
|
||||
public class Authority implements Serializable, Persistable<String> {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@NotNull
|
||||
@Size(max = 50)
|
||||
@Id
|
||||
@Column(name = "name", length = 50, nullable = false)
|
||||
private String name;
|
||||
|
||||
@org.springframework.data.annotation.Transient
|
||||
@Transient
|
||||
private boolean isPersisted;
|
||||
|
||||
// jhipster-needle-entity-add-field - JHipster will add fields here
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public Authority name(String name) {
|
||||
this.setName(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@PostLoad
|
||||
@PostPersist
|
||||
public void updateEntityState() {
|
||||
this.setIsPersisted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@org.springframework.data.annotation.Transient
|
||||
@Transient
|
||||
@Override
|
||||
public boolean isNew() {
|
||||
return !this.isPersisted;
|
||||
}
|
||||
|
||||
public Authority setIsPersisted() {
|
||||
this.isPersisted = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
// jhipster-needle-entity-add-getters-setters - JHipster will add getters and setters here
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof Authority)) {
|
||||
return false;
|
||||
}
|
||||
return getName() != null && getName().equals(((Authority) o).getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(getName());
|
||||
}
|
||||
|
||||
// prettier-ignore
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Authority{" +
|
||||
"name=" + getName() +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
package com.sisvietnamvn.web.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.sisvietnamvn.web.config.Constants;
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hibernate.annotations.BatchSize;
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
/**
|
||||
* A user.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "jhi_user")
|
||||
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
|
||||
public class User extends AbstractAuditingEntity<Long> implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
|
||||
@SequenceGenerator(name = "sequenceGenerator")
|
||||
@Column(name = "id")
|
||||
private Long id;
|
||||
|
||||
@NotNull
|
||||
@Pattern(regexp = Constants.LOGIN_REGEX)
|
||||
@Size(min = 1, max = 50)
|
||||
@Column(name = "login", length = 50, unique = true, nullable = false)
|
||||
private String login;
|
||||
|
||||
@JsonIgnore
|
||||
@NotNull
|
||||
@Size(min = 60, max = 60)
|
||||
@Column(name = "password_hash", length = 60, nullable = false)
|
||||
private String password;
|
||||
|
||||
@Size(max = 50)
|
||||
@Column(name = "first_name", length = 50)
|
||||
private String firstName;
|
||||
|
||||
@Size(max = 50)
|
||||
@Column(name = "last_name", length = 50)
|
||||
private String lastName;
|
||||
|
||||
@Email
|
||||
@Size(min = 5, max = 254)
|
||||
@Column(name = "email", length = 254, unique = true)
|
||||
private String email;
|
||||
|
||||
@NotNull
|
||||
@Column(name = "activated", nullable = false)
|
||||
private boolean activated = false;
|
||||
|
||||
@Size(min = 2, max = 10)
|
||||
@Column(name = "lang_key", length = 10)
|
||||
private String langKey;
|
||||
|
||||
@Size(max = 256)
|
||||
@Column(name = "image_url", length = 256)
|
||||
private String imageUrl;
|
||||
|
||||
@Size(max = 20)
|
||||
@Column(name = "activation_key", length = 20)
|
||||
@JsonIgnore
|
||||
private String activationKey;
|
||||
|
||||
@Size(max = 20)
|
||||
@Column(name = "reset_key", length = 20)
|
||||
@JsonIgnore
|
||||
private String resetKey;
|
||||
|
||||
@Column(name = "reset_date")
|
||||
private Instant resetDate = null;
|
||||
|
||||
@JsonIgnore
|
||||
@ManyToMany
|
||||
@JoinTable(
|
||||
name = "jhi_user_authority",
|
||||
joinColumns = { @JoinColumn(name = "user_id", referencedColumnName = "id") },
|
||||
inverseJoinColumns = { @JoinColumn(name = "authority_name", referencedColumnName = "name") }
|
||||
)
|
||||
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
|
||||
@BatchSize(size = 20)
|
||||
private Set<Authority> authorities = new HashSet<>();
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getLogin() {
|
||||
return login;
|
||||
}
|
||||
|
||||
// Lowercase the login before saving it in database
|
||||
public void setLogin(String login) {
|
||||
this.login = StringUtils.lowerCase(login, Locale.ENGLISH);
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getImageUrl() {
|
||||
return imageUrl;
|
||||
}
|
||||
|
||||
public void setImageUrl(String imageUrl) {
|
||||
this.imageUrl = imageUrl;
|
||||
}
|
||||
|
||||
public boolean isActivated() {
|
||||
return activated;
|
||||
}
|
||||
|
||||
public void setActivated(boolean activated) {
|
||||
this.activated = activated;
|
||||
}
|
||||
|
||||
public String getActivationKey() {
|
||||
return activationKey;
|
||||
}
|
||||
|
||||
public void setActivationKey(String activationKey) {
|
||||
this.activationKey = activationKey;
|
||||
}
|
||||
|
||||
public String getResetKey() {
|
||||
return resetKey;
|
||||
}
|
||||
|
||||
public void setResetKey(String resetKey) {
|
||||
this.resetKey = resetKey;
|
||||
}
|
||||
|
||||
public Instant getResetDate() {
|
||||
return resetDate;
|
||||
}
|
||||
|
||||
public void setResetDate(Instant resetDate) {
|
||||
this.resetDate = resetDate;
|
||||
}
|
||||
|
||||
public String getLangKey() {
|
||||
return langKey;
|
||||
}
|
||||
|
||||
public void setLangKey(String langKey) {
|
||||
this.langKey = langKey;
|
||||
}
|
||||
|
||||
public Set<Authority> getAuthorities() {
|
||||
return authorities;
|
||||
}
|
||||
|
||||
public void setAuthorities(Set<Authority> authorities) {
|
||||
this.authorities = authorities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof User)) {
|
||||
return false;
|
||||
}
|
||||
return id != null && id.equals(((User) o).id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// see https://vladmihalcea.com/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/
|
||||
return getClass().hashCode();
|
||||
}
|
||||
|
||||
// prettier-ignore
|
||||
@Override
|
||||
public String toString() {
|
||||
return "User{" +
|
||||
"login='" + login + '\'' +
|
||||
", firstName='" + firstName + '\'' +
|
||||
", lastName='" + lastName + '\'' +
|
||||
", email='" + email + '\'' +
|
||||
", imageUrl='" + imageUrl + '\'' +
|
||||
", activated='" + activated + '\'' +
|
||||
", langKey='" + langKey + '\'' +
|
||||
", activationKey='" + activationKey + '\'' +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Domain objects.
|
||||
*/
|
||||
package com.sisvietnamvn.web.domain;
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.sisvietnamvn.web.management;
|
||||
|
||||
import io.micrometer.core.instrument.Counter;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class SecurityMetersService {
|
||||
|
||||
public static final String INVALID_TOKENS_METER_NAME = "security.authentication.invalid-tokens";
|
||||
public static final String INVALID_TOKENS_METER_DESCRIPTION =
|
||||
"Indicates validation error count of the tokens presented by the clients.";
|
||||
public static final String INVALID_TOKENS_METER_BASE_UNIT = "errors";
|
||||
public static final String INVALID_TOKENS_METER_CAUSE_DIMENSION = "cause";
|
||||
|
||||
private final Counter tokenInvalidSignatureCounter;
|
||||
private final Counter tokenExpiredCounter;
|
||||
private final Counter tokenUnsupportedCounter;
|
||||
private final Counter tokenMalformedCounter;
|
||||
|
||||
public SecurityMetersService(MeterRegistry registry) {
|
||||
this.tokenInvalidSignatureCounter = invalidTokensCounterForCauseBuilder("invalid-signature").register(registry);
|
||||
this.tokenExpiredCounter = invalidTokensCounterForCauseBuilder("expired").register(registry);
|
||||
this.tokenUnsupportedCounter = invalidTokensCounterForCauseBuilder("unsupported").register(registry);
|
||||
this.tokenMalformedCounter = invalidTokensCounterForCauseBuilder("malformed").register(registry);
|
||||
}
|
||||
|
||||
private Counter.Builder invalidTokensCounterForCauseBuilder(String cause) {
|
||||
return Counter.builder(INVALID_TOKENS_METER_NAME)
|
||||
.baseUnit(INVALID_TOKENS_METER_BASE_UNIT)
|
||||
.description(INVALID_TOKENS_METER_DESCRIPTION)
|
||||
.tag(INVALID_TOKENS_METER_CAUSE_DIMENSION, cause);
|
||||
}
|
||||
|
||||
public void trackTokenInvalidSignature() {
|
||||
this.tokenInvalidSignatureCounter.increment();
|
||||
}
|
||||
|
||||
public void trackTokenExpired() {
|
||||
this.tokenExpiredCounter.increment();
|
||||
}
|
||||
|
||||
public void trackTokenUnsupported() {
|
||||
this.tokenUnsupportedCounter.increment();
|
||||
}
|
||||
|
||||
public void trackTokenMalformed() {
|
||||
this.tokenMalformedCounter.increment();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Application management.
|
||||
*/
|
||||
package com.sisvietnamvn.web.management;
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Application root.
|
||||
*/
|
||||
package com.sisvietnamvn.web;
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.sisvietnamvn.web.repository;
|
||||
|
||||
import com.sisvietnamvn.web.domain.Authority;
|
||||
import org.springframework.data.jpa.repository.*;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* Spring Data JPA repository for the Authority entity.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@Repository
|
||||
public interface AuthorityRepository extends JpaRepository<Authority, String> {}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user