Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Editors feature should be global #144

Merged
merged 1 commit into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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