Skip to content

Commit

Permalink
Editors feature should be global
Browse files Browse the repository at this point in the history
  • Loading branch information
mczachurski committed Oct 15, 2024
1 parent 79a9888 commit dddb83e
Show file tree
Hide file tree
Showing 11 changed files with 257 additions and 31 deletions.
2 changes: 2 additions & 0 deletions Sources/VernissageServer/Application+Configure.swift
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ extension Application {
self.migrations.add(TrendingHashtag.AddAmountField())
self.migrations.add(TrendingStatus.AddAmountField())
self.migrations.add(TrendingUser.AddAmountField())
self.migrations.add(FeaturedStatus.ChangeUniqueIndex())
self.migrations.add(FeaturedUser.ChangeUniqueIndex())

try await self.autoMigrate()
}
Expand Down
2 changes: 0 additions & 2 deletions Sources/VernissageServer/Controllers/StatusesController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2078,7 +2078,6 @@ struct StatusesController {
}

if try await FeaturedStatus.query(on: request.db)
.filter(\.$user.$id == authorizationPayloadId)
.filter(\.$status.$id == statusId)
.first() == nil {
let id = request.application.services.snowflakeService.generate()
Expand Down Expand Up @@ -2215,7 +2214,6 @@ struct StatusesController {
}

if let featuredStatus = try await FeaturedStatus.query(on: request.db)
.filter(\.$user.$id == authorizationPayloadId)
.filter(\.$status.$id == statusId)
.first() {
try await featuredStatus.delete(on: request.db)
Expand Down
15 changes: 0 additions & 15 deletions Sources/VernissageServer/Controllers/UsersController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1504,11 +1504,6 @@ struct UsersController {
}
}






/// Feature specific user.
///
/// This endpoint is used to add the user to a special list of featured users.
Expand Down Expand Up @@ -1581,7 +1576,6 @@ struct UsersController {
}

if try await FeaturedUser.query(on: request.db)
.filter(\.$user.$id == authorizationPayloadId)
.filter(\.$featuredUser.$id == userId)
.first() == nil {
let id = request.application.services.snowflakeService.generate()
Expand Down Expand Up @@ -1652,10 +1646,6 @@ struct UsersController {
@Sendable
func unfeature(request: Request) async throws -> UserDto {
let usersService = request.application.services.usersService

guard let authorizationPayloadId = request.userId else {
throw Abort(.forbidden)
}

guard let userName = request.parameters.get("name") else {
throw Abort(.badRequest)
Expand All @@ -1675,7 +1665,6 @@ struct UsersController {
}

if let featureUser = try await FeaturedUser.query(on: request.db)
.filter(\.$user.$id == authorizationPayloadId)
.filter(\.$featuredUser.$id == userId)
.first() {
try await featureUser.delete(on: request.db)
Expand All @@ -1695,10 +1684,6 @@ struct UsersController {
return userProfile
}





private func relationship(on request: Request, sourceId: Int64, targetUser: User) async throws -> RelationshipDto {
let targetUserId = try targetUser.requireID()
let relationshipsService = request.application.services.relationshipsService
Expand Down
47 changes: 47 additions & 0 deletions Sources/VernissageServer/Migrations/CreateFeaturedStatuses.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import Vapor
import Fluent
import SQLKit
import SQLiteKit

extension FeaturedStatus {
struct CreateFeaturedStatuses: AsyncMigration {
Expand Down Expand Up @@ -40,4 +41,50 @@ extension FeaturedStatus {
try await database.schema(FeaturedStatus.schema).delete()
}
}

struct ChangeUniqueIndex: AsyncMigration {
func prepare(on database: Database) async throws {
// SQLite only supports adding columns in ALTER TABLE statements.
if let _ = database as? SQLiteDatabase {
return
}

try await database
.schema(FeaturedStatus.schema)
.deleteUnique(on: "statusId", "userId")
.update()

try await database
.schema(FeaturedStatus.schema)
.unique(on: "statusId")
.update()

if let sqlDatabase = database as? SQLDatabase {
try await sqlDatabase
.drop(index: "\(FeaturedStatus.schema)_statusIdIndex")
.run()

try await sqlDatabase
.drop(index: "\(FeaturedStatus.schema)_userIdIndex")
.run()
}
}

func revert(on database: Database) async throws {
// SQLite only supports adding columns in ALTER TABLE statements.
if let _ = database as? SQLiteDatabase {
return
}

try await database
.schema(FeaturedStatus.schema)
.deleteUnique(on: "statusId")
.update()

try await database
.schema(FeaturedStatus.schema)
.unique(on: "statusId", "userId")
.update()
}
}
}
47 changes: 47 additions & 0 deletions Sources/VernissageServer/Migrations/CreateFeaturedUsers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import Vapor
import Fluent
import SQLKit
import SQLiteKit

extension FeaturedUser {
struct CreateFeaturedUsers: AsyncMigration {
Expand Down Expand Up @@ -40,4 +41,50 @@ extension FeaturedUser {
try await database.schema(FeaturedUser.schema).delete()
}
}

struct ChangeUniqueIndex: AsyncMigration {
func prepare(on database: Database) async throws {
// SQLite only supports adding columns in ALTER TABLE statements.
if let _ = database as? SQLiteDatabase {
return
}

try await database
.schema(FeaturedUser.schema)
.deleteUnique(on: "featuredUserId", "userId")
.update()

try await database
.schema(FeaturedUser.schema)
.unique(on: "featuredUserId")
.update()

if let sqlDatabase = database as? SQLDatabase {
try await sqlDatabase
.drop(index: "\(FeaturedUser.schema)_featuredUserIdIndex")
.run()

try await sqlDatabase
.drop(index: "\(FeaturedUser.schema)_userIdIndex")
.run()
}
}

func revert(on database: Database) async throws {
// SQLite only supports adding columns in ALTER TABLE statements.
if let _ = database as? SQLiteDatabase {
return
}

try await database
.schema(FeaturedUser.schema)
.deleteUnique(on: "featuredUserId")
.update()

try await database
.schema(FeaturedUser.schema)
.unique(on: "featuredUserId", "userId")
.update()
}
}
}
7 changes: 1 addition & 6 deletions Sources/VernissageServer/Services/StatusesService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1338,13 +1338,8 @@ final class StatusesService: StatusesServiceType {
return bookmarkedStatuses.map({ $0.$status.id })
}

private func statusIsFeatured(on request: Request, statusId: Int64) async throws -> Bool {
guard let authorizationPayloadId = request.userId else {
return false
}

private func statusIsFeatured(on request: Request, statusId: Int64) async throws -> Bool {
let amount = try await FeaturedStatus.query(on: request.db)
.filter(\.$user.$id == authorizationPayloadId)
.filter(\.$status.$id == statusId)
.count()

Expand Down
7 changes: 1 addition & 6 deletions Sources/VernissageServer/Services/UsersService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -959,13 +959,8 @@ final class UsersService: UsersServiceType {
return userDto
}

private func userIsFeatured(on request: Request, userId: Int64) async throws -> Bool {
guard let authorizationPayloadId = request.userId else {
return false
}

private func userIsFeatured(on request: Request, userId: Int64) async throws -> Bool {
let amount = try await FeaturedUser.query(on: request.db)
.filter(\.$user.$id == authorizationPayloadId)
.filter(\.$featuredUser.$id == userId)
.count()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,64 @@ extension ControllersTests {
#expect(statusDto.featured == true, "Status should be marked as featured.")
}

@Test("Status should be featured only once")
func statusShouldBeFeaturedOnlyOnce() async throws {

// Arrange.
let user1 = try await application.createUser(userName: "zibifokimo")
let user2 = try await application.createUser(userName: "zicofokimo")
try await application.attach(user: user1, role: Role.moderator)
try await application.attach(user: user2, role: Role.moderator)

let (statuses, attachments) = try await application.createStatuses(user: user1, notePrefix: "Note Featured", amount: 1)
defer {
application.clearFiles(attachments: attachments)
}

_ = try await application.createFeaturedStatus(user: user1, status: statuses.first!)

// Act.
_ = try application.getResponse(
as: .user(userName: "zicofokimo", password: "p@ssword"),
to: "/statuses/\(statuses.first!.requireID())/feature",
method: .POST,
decodeTo: StatusDto.self
)

// Assert.
let allFeaturedStatuses = try await application.getAllFeaturedStatuses()
#expect(allFeaturedStatuses.count { $0.status.id == statuses.first!.id } == 1, "Status wasn't featured once.")
}

@Test("Status should be mark as featured even if other moderator featured status")
func statusShouldBeFeaturedEvenIfOtherModeratorFeaturedStatus() async throws {

// Arrange.
let user1 = try await application.createUser(userName: "andyfokimo")
let user2 = try await application.createUser(userName: "arrinfokimo")
try await application.attach(user: user1, role: Role.moderator)
try await application.attach(user: user2, role: Role.moderator)

let (statuses, attachments) = try await application.createStatuses(user: user1, notePrefix: "Note Featured", amount: 1)
defer {
application.clearFiles(attachments: attachments)
}

_ = try await application.createFeaturedStatus(user: user1, status: statuses.first!)

// Act.
let statusDto = try application.getResponse(
as: .user(userName: "arrinfokimo", password: "p@ssword"),
to: "/statuses/\(statuses.first!.requireID())",
method: .GET,
decodeTo: UserDto.self
)

// Assert.
#expect(statusDto.id != nil, "Status wasn't returned.")
#expect(statusDto.featured == true, "Status should be marked as featured.")
}

@Test("Forbidden should be returned for regular user")
func forbiddenShouldbeReturnedForRegularUser() async throws {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,32 @@ extension ControllersTests {
#expect(statusDto.featured == false, "Status should be marked as unfeatured.")
}

@Test("Status should be unfeatured even if other moderator feature status")
func statusShouldBeUnfeaturedEvenIfOtherModeratorFeatureStatus() async throws {

// Arrange.
let user1 = try await application.createUser(userName: "zibirojon")
let user2 = try await application.createUser(userName: "zicorojon")
let (statuses, attachments) = try await application.createStatuses(user: user1, notePrefix: "Note Unfavorited", amount: 1)
defer {
application.clearFiles(attachments: attachments)
}
_ = try await application.createFeaturedStatus(user: user1, status: statuses.first!)
try await application.attach(user: user2, role: Role.moderator)

// Act.
_ = try application.getResponse(
as: .user(userName: "zicorojon", password: "p@ssword"),
to: "/statuses/\(statuses.first!.requireID())/unfeature",
method: .POST,
decodeTo: StatusDto.self
)

// Assert.
let allFeaturedStatuses = try await application.getAllFeaturedStatuses()
#expect(allFeaturedStatuses.contains { $0.status.id == statuses.first!.id } == false, "Status wasn't unfeatured.")
}

@Test("Forbidden should be returned for regular user")
func forbiddenShouldbeReturnedForRegularUser() async throws {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,55 @@ extension ControllersTests {
)

// Assert.
#expect(userDto.id != nil, "User wasn't featured.")
#expect(userDto.id != nil, "User wasn't returned.")
#expect(userDto.featured == true, "User should be marked as featured.")
}

@Test("User should be featured only once")
func userShouldBeFeaturedOnlyOnce() async throws {

// Arrange.
let user1 = try await application.createUser(userName: "nicoleborin")
let user2 = try await application.createUser(userName: "vikiborin")
let user3 = try await application.createUser(userName: "franborin")
try await application.attach(user: user1, role: Role.moderator)
try await application.attach(user: user2, role: Role.moderator)
_ = try await application.createFeaturedUser(user: user1, featuredUser: user3)

// Act.
_ = try application.getResponse(
as: .user(userName: "vikiborin", password: "p@ssword"),
to: "/users/@\(user3.userName)/feature",
method: .POST,
decodeTo: UserDto.self
)

// Assert.
let allFeaturedUsers = try await application.getAllFeaturedUsers()
#expect(allFeaturedUsers.count { $0.featuredUser.id == user3.id } == 1, "User wasn't featured once.")
}

@Test("User should be mark as featured even if other moderator featured user")
func userShouldBeFeaturedEvenIfOtherModeratorFeaturedUser() async throws {

// Arrange.
let user1 = try await application.createUser(userName: "zibiborin")
let user2 = try await application.createUser(userName: "zackborin")
let user3 = try await application.createUser(userName: "zomoborin")
try await application.attach(user: user1, role: Role.moderator)
try await application.attach(user: user2, role: Role.moderator)
_ = try await application.createFeaturedUser(user: user1, featuredUser: user3)

// Act.
let userDto = try application.getResponse(
as: .user(userName: "zackborin", password: "p@ssword"),
to: "/users/@\(user3.userName)",
method: .GET,
decodeTo: UserDto.self
)

// Assert.
#expect(userDto.id != nil, "User wasn't returned.")
#expect(userDto.featured == true, "User should be marked as featured.")
}

Expand Down
Loading

0 comments on commit dddb83e

Please sign in to comment.