Skip to content
This repository was archived by the owner on Apr 20, 2024. It is now read-only.

Commit 25447f8

Browse files
committed
Merge feature/align-with-submissions into vapor-3
2 parents 328ad1d + b5d77dc commit 25447f8

34 files changed

+664
-766
lines changed

Package.swift

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,37 +11,37 @@ let package = Package(
1111
targets: ["AdminPanel"]),
1212
],
1313
dependencies: [
14-
.package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"),
15-
.package(url: "https://github.com/vapor/fluent.git", from: "3.0.0"),
16-
.package(url: "https://github.com/vapor/fluent-mysql.git", from: "3.0.0"),
17-
.package(url: "https://github.com/vapor/leaf.git", from: "3.0.0"),
18-
.package(url: "https://github.com/vapor/auth.git", from: "2.0.0"),
19-
20-
.package(url: "https://github.com/nodes-vapor/sugar.git", from: "3.0.0"),
21-
.package(url: "https://github.com/nodes-vapor/flash.git", from: "4.0.0"),
22-
.package(url: "https://github.com/nodes-vapor/bootstrap.git", from: "3.0.0"),
14+
.package(url: "https://github.com/nodes-vapor/bootstrap.git", from: "4.0.0-rc"),
15+
.package(url: "https://github.com/nodes-vapor/flash.git", from: "5.0.0-rc"),
16+
.package(url: "https://github.com/nodes-vapor/paginator.git", from: "3.2.0"),
2317
.package(url: "https://github.com/nodes-vapor/reset.git", from: "1.0.0-rc"),
24-
.package(url: "https://github.com/nodes-vapor/submissions.git", from: "1.0.0-beta"),
25-
.package(url: "https://github.com/nodes-vapor/paginator.git", .upToNextMinor(from:"3.0.0")),
18+
.package(url: "https://github.com/nodes-vapor/submissions.git", from: "2.0.0-rc"),
19+
.package(url: "https://github.com/nodes-vapor/sugar.git", from: "4.0.0-rc"),
2620

2721
.package(url: "https://github.com/twof/VaporMailgunService.git", from: "1.1.0"),
22+
23+
.package(url: "https://github.com/vapor/auth.git", from: "2.0.0"),
24+
.package(url: "https://github.com/vapor/fluent-mysql.git", from: "3.0.0"),
25+
.package(url: "https://github.com/vapor/fluent.git", from: "3.0.0"),
26+
.package(url: "https://github.com/vapor/leaf.git", from: "3.0.0"),
27+
.package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"),
2828
],
2929
targets: [
3030
.target(
3131
name: "AdminPanel",
3232
dependencies: [
33-
"Vapor",
33+
"Authentication",
34+
"Bootstrap",
35+
"Flash",
3436
"Fluent",
3537
"FluentMySQL",
3638
"Leaf",
37-
"Authentication",
38-
"Sugar",
39-
"Flash",
40-
"Bootstrap",
39+
"Mailgun",
40+
"Paginator",
4141
"Reset",
4242
"Submissions",
43-
"Mailgun",
44-
"Paginator"
43+
"Sugar",
44+
"Vapor",
4545
]),
4646
.testTarget(
4747
name: "AdminPanelTests",

Public/AdminPanel/css/dashboard.css

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,21 @@ body {
99
}
1010

1111
.sticky-top {
12-
position: fixed;
13-
top: 0;
14-
right: 0;
15-
left: 0;
16-
z-index: 1030;
12+
position: fixed;
13+
top: 0;
14+
right: 0;
15+
left: 0;
16+
z-index: 1030;
1717
}
1818

1919
.sidebar {
20-
position: fixed;
21-
top: 0;
22-
bottom: 0;
23-
left: 0;
24-
z-index: 100;
25-
padding: 48px 0 0;
26-
box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.1);
20+
position: fixed;
21+
top: 0;
22+
bottom: 0;
23+
left: 0;
24+
z-index: 100;
25+
padding: 48px 0 0;
26+
box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.1);
2727
}
2828

2929
.sidebar-sticky {
@@ -67,11 +67,15 @@ body {
6767
}
6868

6969
[role="main"] {
70-
padding-top: 48px;
70+
padding-top: 48px;
7171
}
7272

7373
.alerts {
74-
padding-top: 1rem;
74+
padding-top: 1rem;
75+
}
76+
77+
.alert {
78+
overflow: auto;
7579
}
7680

7781
.navbar-brand {

Sources/AdminPanel/Commands/AdminPanelUser+Seedable.swift

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,12 @@ extension AdminPanelUser: Seedable {
4646
let email = command.options[Keys.Options.email] ?? AdminPanelUser.defaultEmail
4747
let name = command.options[Keys.Options.name] ?? AdminPanelUser.defaultName
4848

49-
try self.init(Registration(
49+
try self.init(
5050
email: email,
5151
name: name,
5252
title: "Tester",
53-
avatarURL: nil,
5453
role: .superAdmin,
55-
password: password,
56-
passwordRepeat: password,
57-
shouldResetPassword: false
58-
))
54+
password: AdminPanelUser.hashPassword(password)
55+
)
5956
}
6057
}

Sources/AdminPanel/Configs/AdminPanelConfig.swift

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Fluent
22
import JWT
3+
import Reset
34
import Sugar
45
import Vapor
56

@@ -34,11 +35,11 @@ public struct AdminPanelConfig<U: AdminPanelUserType>: Service {
3435
public let views: AdminPanelViews
3536
public let controllers: AdminPanelControllers<U>
3637
public let sidebarMenuPathGenerator: SidebarMenuPathGenerator<U.Role>
38+
public let resetEndpoints: ResetEndpoints
3739
public let resetPasswordEmail: ResetPasswordEmail
3840
public let resetSigner: JWTSigner
3941
public let specifyPasswordEmail: SpecifyPasswordEmail
4042
public let environment: Environment
41-
public let tagTemplatePaths: TagTemplatePaths
4243

4344
public init(
4445
name: String,
@@ -48,23 +49,28 @@ public struct AdminPanelConfig<U: AdminPanelUserType>: Service {
4849
controllers: AdminPanelControllers<U> = .default,
4950
sidebarMenuPathGenerator: @escaping SidebarMenuPathGenerator<U.Role>
5051
= U.Role.sidebarMenuPathGenerator,
52+
resetEndpoints: ResetEndpoints = ResetEndpoints(
53+
renderResetPasswordRequest: "/admin/users/reset-password/request",
54+
resetPasswordRequest: "/admin/users/reset-password/request",
55+
renderResetPassword: "/admin/users/reset-password",
56+
resetPassword: "/admin/users/reset-password"
57+
),
5158
resetPasswordEmail: ResetPasswordEmail = .default,
5259
resetSigner: JWTSigner,
5360
specifyPasswordEmail: SpecifyPasswordEmail = .default,
54-
environment: Environment,
55-
tagTemplatePaths: TagTemplatePaths = TagTemplatePaths()
61+
environment: Environment
5662
) {
5763
self.name = name
5864
self.baseURL = baseURL
5965
self.endpoints = endpoints
6066
self.views = views
6167
self.controllers = controllers
6268
self.sidebarMenuPathGenerator = sidebarMenuPathGenerator
69+
self.resetEndpoints = resetEndpoints
6370
self.resetPasswordEmail = resetPasswordEmail
6471
self.resetSigner = resetSigner
6572
self.specifyPasswordEmail = specifyPasswordEmail
6673
self.environment = environment
67-
self.tagTemplatePaths = tagTemplatePaths
6874
}
6975
}
7076

Sources/AdminPanel/Configs/TagTemplatePaths.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// Configuration for template paths used when rendering tags.
22
public struct TagTemplatePaths {
3+
34
/// Path to template for Quill WYSIWYG field.
45
public let wysiwygField: String
56

Sources/AdminPanel/Controllers/AdminPanelUserController.swift

Lines changed: 51 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,16 @@ public final class AdminPanelUserController
2424

2525
public func renderList(_ req: Request) throws -> Future<Response> {
2626
let config: AdminPanelConfig<U> = try req.make()
27-
let paginator: Future<OffsetPaginator<U>> = try U.query(on: req).paginate(for: req)
28-
return paginator
29-
.flatMap(to: Response.self) { paginator in
30-
return try req.privateContainer
31-
.make(LeafRenderer.self)
27+
return try U.query(on: req)
28+
.paginate(for: req)
29+
.flatMap(to: Response.self) { (paginator: OffsetPaginator) in
30+
try req
31+
.view()
3232
.render(
3333
config.views.adminPanelUser.index,
3434
MultipleUsers(users: paginator.data ?? []),
35-
userInfo: try paginator.userInfo()
35+
userInfo: try paginator.userInfo(),
36+
on: req
3637
)
3738
.encode(for: req)
3839
}
@@ -42,29 +43,25 @@ public final class AdminPanelUserController
4243

4344
public func renderCreate(_ req: Request) throws -> Future<Response> {
4445
let config: AdminPanelConfig<U> = try req.make()
45-
try req.populateFields(U.self)
46-
return try req.privateContainer
47-
.make(LeafRenderer.self)
48-
.render(config.views.adminPanelUser.editAndCreate)
46+
try req.addFields(forType: U.self)
47+
48+
return try req
49+
.view()
50+
.render(config.views.adminPanelUser.editAndCreate, on: req)
4951
.encode(for: req)
5052
}
5153

5254
public func create(_ req: Request) throws -> Future<Response> {
5355
let config: AdminPanelConfig<U> = try req.make()
54-
let submission = try req.content.decode(U.Submission.self)
5556

56-
return submission
57-
.createValid(on: req)
57+
return U
58+
.create(on: req)
5859
.save(on: req)
5960
.flatTry { user in
60-
return submission.flatTry { submission in
61-
return try user.didCreate(with: submission, on: req)
62-
}
63-
.transform(to: ())
61+
try user.didCreate(on: req)
6462
}
65-
.map(to: Response.self) { user in
66-
req
67-
.redirect(to: "/admin/users")
63+
.map { user in
64+
req.redirect(to: config.endpoints.adminPanelUserBasePath)
6865
.flash(
6966
.success,
7067
"The user with email '\(user[keyPath: U.usernameKey])' " +
@@ -73,58 +70,57 @@ public final class AdminPanelUserController
7370
}
7471
.catchFlatMap(handleValidationError(
7572
path: config.views.adminPanelUser.editAndCreate,
76-
on: req)
77-
)
73+
on: req
74+
))
7875
}
7976

8077
// MARK: Edit user
8178

8279
public func renderEditMe(_ req: Request) throws -> Future<Response> {
83-
let user = try req.requireAuthenticated(U.self)
84-
return try renderEdit(req, user: Future.transform(to: user, on: req))
80+
return try renderEdit(req, user: try req.requireAuthenticated(U.self))
8581
}
8682

8783
public func renderEditUser(_ req: Request) throws -> Future<Response> {
88-
let user = try req.parameters.next(U.self)
89-
return try renderEdit(req, user: user)
84+
return try req.parameters
85+
.next(U.self)
86+
.flatMap { user in
87+
try self.renderEdit(req, user: user)
88+
}
9089
}
9190

92-
private func renderEdit(_ req: Request, user: Future<U>) throws -> Future<Response> {
91+
private func renderEdit(_ req: Request, user: U) throws -> Future<Response> {
9392
let adminPanelUser: U = try req.requireAuthenticated()
93+
try adminPanelUser.requireRole(user.role) // A user may not edit a user of a higher role
9494

95+
try req.addFields(given: user)
9596
let config: AdminPanelConfig<U> = try req.make()
96-
return user
97-
.try { user in
98-
// A user cannot edit another user of a higher role
99-
try adminPanelUser.requireRole(user.role)
100-
}
101-
.populateFields(on: req)
102-
.flatMap { user in
103-
try req.privateContainer
104-
.make(LeafRenderer.self)
105-
.render(config.views.adminPanelUser.editAndCreate, SingleUser(user: user))
106-
.encode(for: req)
107-
}
97+
98+
return try req
99+
.view()
100+
.render(config.views.adminPanelUser.editAndCreate, SingleUser(user: user), on: req)
101+
.encode(for: req)
108102
}
109103

110104
public func editMe(_ req: Request) throws -> Future<Response> {
111105
let user = try req.requireAuthenticated(U.self)
112-
return try edit(req, user: Future.transform(to: user, on: req))
106+
return try edit(req, user: user)
113107
}
114108

115109
public func editUser(_ req: Request) throws -> Future<Response> {
116-
let user = try req.parameters.next(U.self)
117-
return try edit(req, user: user)
110+
return try req.parameters.next(U.self)
111+
.flatMap { user in
112+
try self.edit(req, user: user)
113+
}
118114
}
119115

120-
private func edit(_ req: Request, user: Future<U>) throws -> Future<Response> {
116+
private func edit(_ req: Request, user: U) throws -> Future<Response> {
121117
let config: AdminPanelConfig<U> = try req.make()
118+
122119
return user
123-
.updateValid(on: req)
120+
.applyUpdate(on: req)
124121
.save(on: req)
125122
.map(to: Response.self) { user in
126-
req
127-
.redirect(to: "/admin/users")
123+
req.redirect(to: config.endpoints.adminPanelUserBasePath)
128124
.flash(
129125
.success,
130126
"The user with username '\(user[keyPath: U.usernameKey])' " +
@@ -133,27 +129,29 @@ public final class AdminPanelUserController
133129
}
134130
.catchFlatMap(handleValidationError(
135131
path: config.views.adminPanelUser.editAndCreate,
136-
context: user.map(to: SingleUser.self) { .init(user: $0) },
137-
on: req)
138-
)
132+
context: SingleUser(user: user),
133+
on: req
134+
))
139135
}
140136

141137
// MARK: Delete user
142138

143139
public func delete(_ req: Request) throws -> Future<Response> {
144140
let auth = try req.requireAuthenticated(U.self)
145141
let user = try req.parameters.next(U.self)
146-
return user.delete(on: req)
142+
let config: AdminPanelConfig<U> = try req.make()
143+
144+
return user
145+
.delete(on: req)
147146
.map(to: Response.self) { user in
148147
guard auth[keyPath: U.usernameKey] != user[keyPath: U.usernameKey] else {
149148
return req
150-
.redirect(to: "/admin/login")
149+
.redirect(to: config.endpoints.adminPanelUserBasePath)
151150
.flash(.success, "Your user has now been deleted.")
152-
153151
}
154152

155153
return req
156-
.redirect(to: "/admin/users")
154+
.redirect(to: config.endpoints.adminPanelUserBasePath)
157155
.flash(
158156
.success,
159157
"The user with username '\(user[keyPath: U.usernameKey])' " +

Sources/AdminPanel/Controllers/DashboardController.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ public final class DashboardController<U: AdminPanelUserType>: DashboardControll
1111
public func renderDashboard(_ req: Request) throws -> Future<Response> {
1212
let config = try req.make(AdminPanelConfig<U>.self)
1313

14-
return try req.privateContainer
15-
.make(LeafRenderer.self)
16-
.render(config.views.dashboard.index)
14+
return try req
15+
.view()
16+
.render(config.views.dashboard.index, on: req)
1717
.encode(for: req)
1818
}
1919
}

0 commit comments

Comments
 (0)