Skip to content

Commit 5292b62

Browse files
committed
Support tags with spaces etc
1 parent b29b7b5 commit 5292b62

File tree

11 files changed

+71
-66
lines changed

11 files changed

+71
-66
lines changed

Sources/SteamPress/Controllers/Admin/PostAdminController.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,15 @@ struct PostAdminController: RouteCollection {
5252

5353
var existingTagsQuery = [EventLoopFuture<BlogTag?>]()
5454
for tagName in data.tags {
55-
try existingTagsQuery.append(tagsRepository.getTag(BlogTag.percentEncodedTagName(from: tagName), on: req))
55+
existingTagsQuery.append(tagsRepository.getTag(tagName, on: req))
5656
}
5757

5858
return existingTagsQuery.flatten(on: req).flatMap { existingTagsWithOptionals in
5959
let existingTags = existingTagsWithOptionals.compactMap { $0 }
6060
var tagsSaves = [EventLoopFuture<BlogTag>]()
6161
for tagName in data.tags {
62-
if try !existingTags.contains { try $0.name == BlogTag.percentEncodedTagName(from: tagName) } {
63-
let tag = try BlogTag(name: tagName)
62+
if !existingTags.contains { $0.name == tagName } {
63+
let tag = BlogTag(name: tagName)
6464
tagsSaves.append(tagsRepository.save(tag, on: req))
6565
}
6666
}
@@ -137,9 +137,9 @@ struct PostAdminController: RouteCollection {
137137

138138
let tagsRepository = try req.make(BlogTagRepository.self)
139139
return tagsRepository.getTags(for: post, on: req).flatMap { existingTags in
140-
let tagsToUnlink = try existingTags.filter { (anExistingTag) -> Bool in
140+
let tagsToUnlink = existingTags.filter { (anExistingTag) -> Bool in
141141
for tagName in data.tags {
142-
if try anExistingTag.name == BlogTag.percentEncodedTagName(from: tagName) {
142+
if anExistingTag.name == tagName {
143143
return false
144144
}
145145
}
@@ -150,15 +150,15 @@ struct PostAdminController: RouteCollection {
150150
removeTagLinkResults.append(tagsRepository.remove(tagToUnlink, from: post, on: req))
151151
}
152152

153-
let newTagsNames = try data.tags.filter { (tagName) -> Bool in
154-
try !existingTags.contains { (existingTag) -> Bool in
155-
try existingTag.name == BlogTag.percentEncodedTagName(from: tagName)
153+
let newTagsNames = data.tags.filter { (tagName) -> Bool in
154+
!existingTags.contains { (existingTag) -> Bool in
155+
existingTag.name == tagName
156156
}
157157
}
158158

159159
var tagCreateSaves = [EventLoopFuture<BlogTag>]()
160160
for newTagName in newTagsNames {
161-
let newTag = try BlogTag(name: newTagName)
161+
let newTag = BlogTag(name: newTagName)
162162
tagCreateSaves.append(tagsRepository.save(newTag, on: req))
163163
}
164164

Sources/SteamPress/Models/BlogTag.swift

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,10 @@ public final class BlogTag: Codable {
77
public var tagID: Int?
88
public var name: String
99

10-
public init(id: Int? = nil, name: String) throws {
10+
public init(id: Int? = nil, name: String) {
1111
self.tagID = id
12-
self.name = try BlogTag.percentEncodedTagName(from: name)
12+
self.name = name
1313
}
1414
}
1515

1616
extension BlogTag: Content {}
17-
18-
extension BlogTag {
19-
static func percentEncodedTagName(from name: String) throws -> String {
20-
guard let percentEncodedName = name.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) else {
21-
throw SteamPressError(identifier: "BlogTag", "Unable to create tag from name \(name)")
22-
}
23-
return percentEncodedName
24-
}
25-
}

Sources/SteamPress/Models/Contexts/BlogIndexPageContext.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
struct BlogIndexPageContext: Encodable {
22
let posts: [ViewBlogPost]
3-
let tags: [BlogTag]
3+
let tags: [ViewBlogTag]
44
let authors: [BlogUser]
55
let pageInformation: BlogGlobalPageInformation
66
let title = "Blog"

Sources/SteamPress/Models/Contexts/ContextViews/ViewBlogPost.swift

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -87,17 +87,9 @@ extension BlogPost {
8787
func toViewPost(authorName: String, authorUsername: String, longFormatter: LongPostDateFormatter, numericFormatter: NumericPostDateFormatter, tags: [BlogTag]) throws -> ViewBlogPost {
8888
let viewPost = try self.toViewPostWithoutTags(authorName: authorName, authorUsername: authorUsername, longFormatter: longFormatter, numericFormatter: numericFormatter)
8989

90-
let viewTags = try tags.map { tag -> ViewBlogTag in
91-
guard let urlEncodedName = tag.name.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) else {
92-
throw SteamPressError(identifier: "ViewBlogPost", "Failed to URL encode tag name")
93-
}
94-
guard let tagID = tag.tagID else {
95-
throw SteamPressError(identifier: "ViewBlogPost", "Tag has no ID")
96-
}
97-
return ViewBlogTag(tagID: tagID, name: tag.name, urlEncodedName: urlEncodedName)
98-
}
90+
let viewTags = try tags.map { try $0.toViewBlogTag() }
9991

100-
return try ViewBlogPost(blogID: viewPost.blogID, title: viewPost.title, contents: viewPost.contents, author: viewPost.author, created: viewPost.created, lastEdited: viewPost.lastEdited, slugUrl: viewPost.slugUrl, published: viewPost.published, longSnippet: viewPost.longSnippet, createdDateLong: viewPost.createdDateLong, createdDateNumeric: viewPost.createdDateNumeric, lastEditedDateNumeric: viewPost.lastEditedDateNumeric, lastEditedDateLong: viewPost.lastEditedDateLong, authorName: viewPost.authorName, authorUsername: viewPost.authorUsername, postImage: viewPost.postImage, postImageAlt: viewPost.postImageAlt, description: viewPost.description, tags: viewTags)
92+
return ViewBlogPost(blogID: viewPost.blogID, title: viewPost.title, contents: viewPost.contents, author: viewPost.author, created: viewPost.created, lastEdited: viewPost.lastEdited, slugUrl: viewPost.slugUrl, published: viewPost.published, longSnippet: viewPost.longSnippet, createdDateLong: viewPost.createdDateLong, createdDateNumeric: viewPost.createdDateNumeric, lastEditedDateNumeric: viewPost.lastEditedDateNumeric, lastEditedDateLong: viewPost.lastEditedDateLong, authorName: viewPost.authorName, authorUsername: viewPost.authorUsername, postImage: viewPost.postImage, postImageAlt: viewPost.postImageAlt, description: viewPost.description, tags: viewTags)
10193
}
10294
}
10395

Sources/SteamPress/Models/Contexts/ContextViews/ViewBlogTag.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,25 @@ struct ViewBlogTag: Encodable {
33
let name: String
44
let urlEncodedName: String
55
}
6+
7+
extension BlogTag {
8+
func toViewBlogTag() throws -> ViewBlogTag {
9+
guard let urlEncodedName = self.name.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) else {
10+
throw SteamPressError(identifier: "ViewBlogPost", "Failed to URL encode tag name")
11+
}
12+
guard let tagID = self.tagID else {
13+
throw SteamPressError(identifier: "ViewBlogPost", "Tag has no ID")
14+
}
15+
return ViewBlogTag(tagID: tagID, name: self.name, urlEncodedName: urlEncodedName)
16+
}
17+
}
18+
19+
extension ViewBlogTag {
20+
21+
static func percentEncodedTagName(from name: String) throws -> String {
22+
guard let percentEncodedName = name.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) else {
23+
throw SteamPressError(identifier: "BlogTag", "Unable to create tag from name \(name)")
24+
}
25+
return percentEncodedName
26+
}
27+
}

Sources/SteamPress/Presenters/ViewBlogPresenter.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ public struct ViewBlogPresenter: BlogPresenter {
99
let viewRenderer = try container.make(ViewRenderer.self)
1010
#warning("Test all the view post stuff")
1111
let viewPosts = try posts.convertToViewBlogPosts(authors: authors, tagsForPosts: tagsForPosts, on: container)
12-
let context = BlogIndexPageContext(posts: viewPosts, tags: tags, authors: authors, pageInformation: pageInformation, paginationTagInformation: paginationTagInfo)
12+
let viewTags = try tags.map { try $0.toViewBlogTag() }
13+
let context = BlogIndexPageContext(posts: viewPosts, tags: viewTags, authors: authors, pageInformation: pageInformation, paginationTagInformation: paginationTagInfo)
1314
return viewRenderer.render("blog/blog", context)
1415
} catch {
1516
return container.future(error: error)

Sources/SteamPress/Repositories/SteamPressRepository.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,6 @@ extension BlogTag: Parameter {
6666
public typealias ResolvedParameter = EventLoopFuture<BlogTag>
6767
public static func resolveParameter(_ parameter: String, on container: Container) throws -> EventLoopFuture<BlogTag> {
6868
let tagRepository = try container.make(BlogTagRepository.self)
69-
guard let encodedName = parameter.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) else {
70-
throw SteamPressError(identifier: "Invalid-Name", "Unable to convert \(parameter) to URL Encoded String")
71-
}
72-
return tagRepository.getTag(encodedName, on: container).unwrap(or: Abort(.notFound))
69+
return tagRepository.getTag(parameter, on: container).unwrap(or: Abort(.notFound))
7370
}
7471
}

Tests/SteamPressTests/BlogTests/TagTests.swift

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -63,22 +63,6 @@ class TagTests: XCTestCase {
6363
XCTAssertEqual(presenter.tagPosts?.first?.title, postData.post.title)
6464
XCTAssertEqual(presenter.tag?.name, tag.name)
6565
}
66-
67-
func testTagNameContainsUrlEncodedName() throws {
68-
let tag = try BlogTag(name: "Luke's Tatooine")
69-
XCTAssertEqual(tag.name, "Luke's%20Tatooine")
70-
}
71-
72-
func testGettingTagViewWithURLEncodedName() throws {
73-
let tagName = "Some Tag"
74-
_ = try testWorld.createTag(tagName)
75-
76-
let urlEncodedName = try XCTUnwrap(tagName.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed))
77-
let response = try testWorld.getResponse(to: "/tags/\(urlEncodedName)")
78-
79-
XCTAssertEqual(response.http.status, .ok)
80-
XCTAssertEqual(presenter.tag?.name.removingPercentEncoding, tagName)
81-
}
8266

8367
func testTagPageGetsCorrectPageInformation() throws {
8468
_ = try testWorld.getResponse(to: tagRequestPath)
@@ -90,6 +74,12 @@ class TagTests: XCTestCase {
9074
XCTAssertEqual(presenter.tagPageInformation?.websiteURL.absoluteString, "/")
9175
}
9276

77+
func testRequestToURLEncodedTag() throws {
78+
_ = try testWorld.createTag("Some tag")
79+
let response = try testWorld.getResponse(to: "/tags/Some%20tag")
80+
XCTAssertEqual(response.http.status, .ok)
81+
}
82+
9383
func testTagPageInformationGetsLoggedInUser() throws {
9484
_ = try testWorld.getResponse(to: tagRequestPath, loggedInUser: postData.author)
9585
XCTAssertEqual(presenter.tagPageInformation?.loggedInUser?.username, postData.author.username)

Tests/SteamPressTests/Helpers/InMemoryRepository.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class InMemoryRepository: BlogTagRepository, BlogPostRepository, BlogUserReposit
6363
}
6464

6565
func addTag(name: String) throws -> BlogTag {
66-
let newTag = try BlogTag(id: tags.count + 1, name: name)
66+
let newTag = BlogTag(id: tags.count + 1, name: name)
6767
tags.append(newTag)
6868
return newTag
6969
}

Tests/SteamPressTests/ViewTests/BlogPresenterTests.swift

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class BlogPresenterTests: XCTestCase {
3434
basicContainer.services.register(LongPostDateFormatter.self)
3535
basicContainer.services.register(NumericPostDateFormatter.self)
3636
viewRenderer = CapturingViewRenderer(worker: basicContainer)
37-
testTag = try! BlogTag(id: 1, name: "Tattoine")
37+
testTag = BlogTag(id: 1, name: "Tattoine")
3838
}
3939

4040
override func tearDown() {
@@ -46,7 +46,7 @@ class BlogPresenterTests: XCTestCase {
4646
// MARK: - All Tags Page
4747

4848
func testParametersAreSetCorrectlyOnAllTagsPage() throws {
49-
let tags = try [BlogTag(id: 0, name: "tag1"), BlogTag(id: 1, name: "tag2")]
49+
let tags = [BlogTag(id: 0, name: "tag1"), BlogTag(id: 1, name: "tag2")]
5050

5151
let pageInformation = buildPageInformation(currentPageURL: allTagsURL)
5252
_ = presenter.allTagsView(on: basicContainer, tags: tags, tagPostCounts: [:], pageInformation: pageInformation)
@@ -66,8 +66,8 @@ class BlogPresenterTests: XCTestCase {
6666
}
6767

6868
func testTagsPageGetsPassedTagsSortedByPostCount() throws {
69-
let tag1 = try BlogTag(id: 0, name: "Engineering")
70-
let tag2 = try BlogTag(id: 1, name: "Tech")
69+
let tag1 = BlogTag(id: 0, name: "Engineering")
70+
let tag2 = BlogTag(id: 1, name: "Tech")
7171
let tags = [tag1, tag2]
7272
let tagPostCount = [0: 5, 1: 20]
7373
let pageInformation = buildPageInformation(currentPageURL: allTagsURL)
@@ -81,8 +81,8 @@ class BlogPresenterTests: XCTestCase {
8181
}
8282

8383
func testTagsPageHandlesNoPostsForTagsCorrectly() throws {
84-
let tag1 = try BlogTag(id: 0, name: "Engineering")
85-
let tag2 = try BlogTag(id: 1, name: "Tech")
84+
let tag1 = BlogTag(id: 0, name: "Engineering")
85+
let tag2 = BlogTag(id: 1, name: "Tech")
8686
let tags = [tag1, tag2]
8787
let tagPostCount = [0: 0, 1: 20]
8888
let pageInformation = buildPageInformation(currentPageURL: allTagsURL)
@@ -94,7 +94,7 @@ class BlogPresenterTests: XCTestCase {
9494
}
9595

9696
func testTwitterHandleNotSetOnAllTagsPageIfNotGiven() throws {
97-
let tags = try [BlogTag(id: 0, name: "tag1"), BlogTag(id: 1, name: "tag2")]
97+
let tags = [BlogTag(id: 0, name: "tag1"), BlogTag(id: 1, name: "tag2")]
9898
let pageInformation = buildPageInformation(currentPageURL: allTagsURL, siteTwitterHandle: nil)
9999
_ = presenter.allTagsView(on: basicContainer, tags: tags, tagPostCounts: [:], pageInformation: pageInformation)
100100

@@ -103,7 +103,7 @@ class BlogPresenterTests: XCTestCase {
103103
}
104104

105105
func testDisqusNameNotSetOnAllTagsPageIfNotGiven() throws {
106-
let tags = try [BlogTag(id: 0, name: "tag1"), BlogTag(id: 1, name: "tag2")]
106+
let tags = [BlogTag(id: 0, name: "tag1"), BlogTag(id: 1, name: "tag2")]
107107
let pageInformation = buildPageInformation(currentPageURL: allTagsURL, disqusName: nil)
108108
_ = presenter.allTagsView(on: basicContainer, tags: tags, tagPostCounts: [:], pageInformation: pageInformation)
109109

@@ -112,7 +112,7 @@ class BlogPresenterTests: XCTestCase {
112112
}
113113

114114
func testGAIdentifierNotSetOnAllTagsPageIfNotGiven() throws {
115-
let tags = try [BlogTag(id: 0, name: "tag1"), BlogTag(id: 1, name: "tag2")]
115+
let tags = [BlogTag(id: 0, name: "tag1"), BlogTag(id: 1, name: "tag2")]
116116
let pageInformation = buildPageInformation(currentPageURL: allTagsURL, googleAnalyticsIdentifier: nil)
117117
_ = presenter.allTagsView(on: basicContainer, tags: tags, tagPostCounts: [:], pageInformation: pageInformation)
118118

@@ -121,7 +121,7 @@ class BlogPresenterTests: XCTestCase {
121121
}
122122

123123
func testLoggedInUserSetOnAllTagsPageIfPassedIn() throws {
124-
let tags = try [BlogTag(id: 0, name: "tag1"), BlogTag(id: 1, name: "tag2")]
124+
let tags = [BlogTag(id: 0, name: "tag1"), BlogTag(id: 1, name: "tag2")]
125125
let user = TestDataBuilder.anyUser()
126126
let pageInformation = buildPageInformation(currentPageURL: allTagsURL, user: user)
127127
_ = presenter.allTagsView(on: basicContainer, tags: tags, tagPostCounts: [:], pageInformation: pageInformation)
@@ -295,8 +295,8 @@ class BlogPresenterTests: XCTestCase {
295295
post.blogID = 1
296296
let post2 = try TestDataBuilder.anyPost(author: author2, title: "Another Title")
297297
post2.blogID = 2
298-
let tag1 = try BlogTag(id: 1, name: "Engineering")
299-
let tag2 = try BlogTag(id: 2, name: "Fun")
298+
let tag1 = BlogTag(id: 1, name: "Engineering")
299+
let tag2 = BlogTag(id: 2, name: "Fun")
300300
let tags = [tag1, tag2]
301301
let currentPage = 2
302302
let totalPages = 10

0 commit comments

Comments
 (0)