├── .codebeatignore ├── .codecov.yml ├── .gitignore ├── Resources └── Views │ └── AdminPanel │ ├── Layout │ ├── Partials │ │ ├── breadcrumb.leaf │ │ ├── Sidebars │ │ │ ├── Menus │ │ │ │ ├── user.leaf │ │ │ │ ├── superadmin.leaf │ │ │ │ ├── shared.leaf │ │ │ │ └── admin.leaf │ │ │ ├── base.leaf │ │ │ ├── user.leaf │ │ │ ├── admin.leaf │ │ │ └── superadmin.leaf │ │ ├── sitetitle.leaf │ │ ├── alerts.leaf │ │ ├── content.leaf │ │ └── navbar.leaf │ └── base.leaf │ ├── Dashboard │ └── index.leaf │ ├── Login │ ├── request-reset-password.leaf │ ├── index.leaf │ └── reset-password.leaf │ ├── Reset │ ├── request-reset-password-email.leaf │ └── new-user-reset-password-email.leaf │ ├── Submissions │ └── Fields │ │ └── quill-wysiwyg.leaf │ └── AdminPanelUser │ ├── index.leaf │ └── edit.leaf ├── Tests ├── LinuxMain.swift └── AdminPanelTests │ ├── XCTestManifests.swift │ └── AdminPanelTests.swift ├── Sources └── AdminPanel │ ├── Models │ ├── AdminPanelUserRole │ │ ├── AdminPanelUserRoleType.swift │ │ └── AdminPanelUserRole.swift │ └── AdminPanelUser │ │ ├── Extensions │ │ ├── AdminPanelUser+Loginable.swift │ │ ├── AdminPanelUser+TemplateDataRepresentable.swift │ │ ├── AdminPanelUser+Updatable.swift │ │ ├── AdminPanelUser+AdminPanelUserType.swift │ │ ├── AdminPanelUser+Creatable.swift │ │ ├── AdminPanelUser+Submittable.swift │ │ └── AdminPanelUser+PasswordResettable.swift │ │ ├── AdminPanelUserType.swift │ │ └── AdminPanelUser.swift │ ├── Helpers │ ├── SidebarMenuPathGenerator.swift │ └── ValidationError.swift │ ├── Configs │ ├── TagTemplatePaths.swift │ └── AdminPanelConfig.swift │ ├── Controllers │ ├── DashboardController.swift │ ├── ResetController.swift │ ├── LoginController.swift │ └── AdminPanelUserController.swift │ ├── Tags │ ├── AvatarURLTag.swift │ ├── SidebarHeadingTag.swift │ ├── CurrentUserTag.swift │ ├── HasRequiredRole.swift │ ├── RequireRoleTag.swift │ ├── SidebarMenuItemTag.swift │ └── AdminPanelConfigTag.swift │ ├── Middlewares │ └── ShouldResetPasswordMiddleware.swift │ ├── Commands │ └── AdminPanelUser+Seedable.swift │ ├── views.swift │ ├── routes.swift │ └── Providers │ └── AdminPanelProvider.swift ├── .swiftlint.yml ├── Public └── AdminPanel │ ├── css │ ├── login.css │ └── dashboard.css │ └── js │ └── modal-confirmation.js ├── .github └── workflows │ └── test.yml ├── LICENSE ├── Package.swift └── README.md /.codebeatignore: -------------------------------------------------------------------------------- 1 | Public/** 2 | Resources/Assets/** 3 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | range: "0...100" 3 | ignore: 4 | - "Tests" 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Packages 2 | .build 3 | .idea 4 | .DS_Store 5 | *.xcodeproj 6 | DerivedData/ 7 | Package.resolved 8 | .swiftpm 9 | -------------------------------------------------------------------------------- /Resources/Views/AdminPanel/Layout/Partials/breadcrumb.leaf: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /Resources/Views/AdminPanel/Layout/Partials/Sidebars/Menus/user.leaf: -------------------------------------------------------------------------------- 1 | #adminPanel:sidebar:heading() { User } 2 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | import AdminPanelTests 4 | 5 | var tests = [XCTestCaseEntry]() 6 | tests += AdminPanelTests.allTests() 7 | XCTMain(tests) -------------------------------------------------------------------------------- /Resources/Views/AdminPanel/Layout/Partials/Sidebars/Menus/superadmin.leaf: -------------------------------------------------------------------------------- 1 | #adminPanel:sidebar:heading() { Super Admin } 2 | -------------------------------------------------------------------------------- /Resources/Views/AdminPanel/Layout/Partials/Sidebars/Menus/shared.leaf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Resources/Views/AdminPanel/Dashboard/index.leaf: -------------------------------------------------------------------------------- 1 | #set("pageTitle") { Dashboard } 2 | 3 | #set("content") { 4 |Hello, world!5 | } 6 | 7 | #embed("AdminPanel/Layout/base") 8 | -------------------------------------------------------------------------------- /Sources/AdminPanel/Models/AdminPanelUserRole/AdminPanelUserRoleType.swift: -------------------------------------------------------------------------------- 1 | public protocol AdminPanelUserRoleType: LosslessStringConvertible, Comparable, Codable { 2 | var menuPath: String { get } 3 | } 4 | -------------------------------------------------------------------------------- /Resources/Views/AdminPanel/Layout/Partials/Sidebars/base.leaf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tests/AdminPanelTests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | #if !os(macOS) 4 | public func allTests() -> [XCTestCaseEntry] { 5 | return [ 6 | testCase(AdminPanelTests.allTests), 7 | ] 8 | } 9 | #endif -------------------------------------------------------------------------------- /Resources/Views/AdminPanel/Layout/Partials/Sidebars/Menus/admin.leaf: -------------------------------------------------------------------------------- 1 | #adminPanel:sidebar:heading() { Admin } 2 | -------------------------------------------------------------------------------- /Resources/Views/AdminPanel/Layout/Partials/Sidebars/user.leaf: -------------------------------------------------------------------------------- 1 | #set("sidebarContent") { 2 | #embed("AdminPanel/Layout/Partials/Sidebars/Menus/shared") 3 | #embed("AdminPanel/Layout/Partials/Sidebars/Menus/user") 4 | } 5 | 6 | #embed("AdminPanel/Layout/Partials/Sidebars/base") -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - Sources 3 | function_body_length: 4 | warning: 60 5 | identifier_name: 6 | min_length: 7 | warning: 2 8 | line_length: 100 9 | disabled_rules: 10 | - opening_brace 11 | - nesting 12 | colon: 13 | flexible_right_spacing: true 14 | -------------------------------------------------------------------------------- /Resources/Views/AdminPanel/Layout/Partials/sitetitle.leaf: -------------------------------------------------------------------------------- 1 | 2 | #adminPanel:config("name") 3 | #if(adminPanel:config("environment") != "production") { 4 | #adminPanel:config("environment") 5 | } 6 | -------------------------------------------------------------------------------- /Resources/Views/AdminPanel/Layout/Partials/Sidebars/admin.leaf: -------------------------------------------------------------------------------- 1 | #set("sidebarContent") { 2 | #embed("AdminPanel/Layout/Partials/Sidebars/Menus/shared") 3 | #embed("AdminPanel/Layout/Partials/Sidebars/Menus/admin") 4 | #embed("AdminPanel/Layout/Partials/Sidebars/Menus/user") 5 | } 6 | 7 | #embed("AdminPanel/Layout/Partials/Sidebars/base") -------------------------------------------------------------------------------- /Sources/AdminPanel/Helpers/SidebarMenuPathGenerator.swift: -------------------------------------------------------------------------------- 1 | public typealias SidebarMenuPathGenerator
9 | We have received a request to reset the password of the user with this e-mail.
10 | If you did not request this, simply ignore and delete this e-mail.
11 |
14 | To reset your password, click the following link:
15 | Reset Password
16 |
19 | If you can't use the link above, please copy paste the following url into your browser:
20 |
21 | #(url)
22 |
26 | This reset password request will expire in #(expire) minutes. 27 |
28 | } 29 | 30 |Best, #reset:config("name")
31 | 32 | -------------------------------------------------------------------------------- /Resources/Views/AdminPanel/Reset/new-user-reset-password-email.leaf: -------------------------------------------------------------------------------- 1 | 2 | 3 |
9 | A new user has been created with this email. To be able to login, a password needs to be specified.
10 | If you did not request this, simply ignore and delete this e-mail.
11 |
14 | To specify your password, click the following link:
15 | Specify Password
16 |
19 | If you can't use the link above, please copy paste the following url into your browser:
20 |
21 | #(url)
22 |
26 | This link will expire in #(expire) days. 27 |
28 | } 29 | 30 |Best, #reset:config("name")
31 | 32 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - master 7 | jobs: 8 | macos: 9 | runs-on: macos-latest 10 | env: 11 | DEVELOPER_DIR: /Applications/Xcode_12.app/Contents/Developer 12 | steps: 13 | - uses: actions/checkout@v2 14 | - run: brew install libressl 15 | - run: xcrun swift test --enable-test-discovery --sanitize=thread -Xcxx "-I/usr/local/opt/openssl/include" -Xlinker "-L/usr/local/opt/openssl/lib" 16 | linux-4_2: 17 | runs-on: ubuntu-latest 18 | container: 19 | image: swift:4.2 20 | steps: 21 | - uses: actions/checkout@v2 22 | - run: swift test 23 | linux: 24 | runs-on: ubuntu-latest 25 | strategy: 26 | fail-fast: false 27 | matrix: 28 | image: 29 | - swift:5.2-focal 30 | - swift:5.3-focal 31 | container: ${{ matrix.image }} 32 | steps: 33 | - uses: actions/checkout@v2 34 | - run: apt-get -qq update && apt-get install -y libssl-dev 35 | - run: swift test --enable-test-discovery --sanitize=thread 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016-2018 Nodes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Resources/Views/AdminPanel/Login/index.leaf: -------------------------------------------------------------------------------- 1 | #set("styles") { 2 | 3 | } 4 | 5 | #set("pageTitle") { Login } 6 | 7 | #set("body") { 8 | 30 | } 31 | 32 | #embed("AdminPanel/Layout/base") 33 | -------------------------------------------------------------------------------- /Resources/Views/AdminPanel/Login/reset-password.leaf: -------------------------------------------------------------------------------- 1 | #set("styles") { 2 | 3 | } 4 | 5 | #set("pageTitle") { Reset Password } 6 | 7 | #set("body") { 8 | 28 | } 29 | 30 | #embed("AdminPanel/Layout/base") 31 | -------------------------------------------------------------------------------- /Sources/AdminPanel/Helpers/ValidationError.swift: -------------------------------------------------------------------------------- 1 | import Flash 2 | import Leaf 3 | import Submissions 4 | import Vapor 5 | 6 | public func handleValidationError( 7 | path: String, 8 | message: String = "Something went wrong while validating the form.", 9 | on req: Request 10 | ) -> (Error) throws -> Future| 14 | | Name | 15 |Title | 16 |18 | | |
|---|---|---|---|---|
| #(user.name) | 25 |#(user.title) | 26 |#(user.email) | 27 |28 | 36 | | 37 |