feat: フィルターの追加と削除を実装

This commit is contained in:
usbharu 2024-06-13 17:23:35 +09:00
parent ea666cf0f8
commit 078547d5ff
19 changed files with 802 additions and 12 deletions

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.application.filter
data class DeleteFilter(val filterId: Long)

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.application.filter
import dev.usbharu.hideout.core.domain.model.filter.Filter
import dev.usbharu.hideout.core.domain.model.filter.FilterAction
import dev.usbharu.hideout.core.domain.model.filter.FilterContext
data class Filter(
val filterId: Long,
val userDetailId: Long,
val name: String,
val filterContext: Set<FilterContext>,
val filterAction: FilterAction,
val filterKeywords: Set<FilterKeyword>,
) {
companion object {
fun of(filter: Filter): dev.usbharu.hideout.core.application.filter.Filter {
return Filter(
filterId = filter.id.id,
userDetailId = filter.userDetailId.id,
name = filter.name.name,
filterContext = filter.filterContext,
filterAction = filter.filterAction,
filterKeywords = filter.filterKeywords.map {
FilterKeyword(
it.id.id,
it.keyword.keyword,
it.mode
)
}.toSet()
)
}
}
}

View File

@ -0,0 +1,25 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.application.filter
import dev.usbharu.hideout.core.domain.model.filter.FilterMode
data class FilterKeyword(
val id: Long,
val keyword: String,
val filterMode: FilterMode,
)

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.application.filter
data class GetFilter(val filterId: Long)

View File

@ -0,0 +1,27 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.application.filter
import dev.usbharu.hideout.core.domain.model.filter.FilterAction
import dev.usbharu.hideout.core.domain.model.filter.FilterContext
data class RegisterFilter(
val filterName: String,
val filterContext: Set<FilterContext>,
val filterAction: FilterAction,
val filterKeywords: Set<RegisterFilterKeyword>,
)

View File

@ -0,0 +1,24 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.application.filter
import dev.usbharu.hideout.core.domain.model.filter.FilterMode
data class RegisterFilterKeyword(
val keyword: String,
val filterMode: FilterMode,
)

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.application.filter
import dev.usbharu.hideout.core.application.shared.AbstractApplicationService
import dev.usbharu.hideout.core.application.shared.CommandExecutor
import dev.usbharu.hideout.core.application.shared.Transaction
import dev.usbharu.hideout.core.domain.model.filter.FilterId
import dev.usbharu.hideout.core.domain.model.filter.FilterRepository
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
@Service
class UserDeleteFilterApplicationService(private val filterRepository: FilterRepository, transaction: Transaction) :
AbstractApplicationService<DeleteFilter, Unit>(
transaction, logger
) {
companion object {
private val logger = LoggerFactory.getLogger(UserDeleteFilterApplicationService::class.java)
}
override suspend fun internalExecute(command: DeleteFilter, executor: CommandExecutor) {
val filter = filterRepository.findByFilterId(FilterId(command.filterId)) ?: throw Exception("not found")
filterRepository.delete(filter)
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.application.filter
import dev.usbharu.hideout.core.application.shared.AbstractApplicationService
import dev.usbharu.hideout.core.application.shared.CommandExecutor
import dev.usbharu.hideout.core.application.shared.Transaction
import dev.usbharu.hideout.core.domain.model.filter.FilterId
import dev.usbharu.hideout.core.domain.model.filter.FilterRepository
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
@Service
class UserGetFilterApplicationService(private val filterRepository: FilterRepository, transaction: Transaction) :
AbstractApplicationService<GetFilter, Filter>(
transaction, logger
) {
override suspend fun internalExecute(command: GetFilter, executor: CommandExecutor): Filter {
val filter = filterRepository.findByFilterId(FilterId(command.filterId)) ?: throw Exception("Not Found")
return Filter.of(filter)
}
companion object {
private val logger = LoggerFactory.getLogger(UserGetFilterApplicationService::class.java)
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.application.filter
import dev.usbharu.hideout.core.application.shared.AbstractApplicationService
import dev.usbharu.hideout.core.application.shared.CommandExecutor
import dev.usbharu.hideout.core.application.shared.Transaction
import dev.usbharu.hideout.core.application.shared.UserDetailGettableCommandExecutor
import dev.usbharu.hideout.core.domain.model.filter.*
import dev.usbharu.hideout.core.domain.model.filter.FilterKeyword
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId
import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
@Service
class UserRegisterFilterApplicationService(
private val idGenerateService: IdGenerateService,
private val filterRepository: FilterRepository,
transaction: Transaction,
) :
AbstractApplicationService<RegisterFilter, Filter>(
transaction, logger
) {
companion object {
private val logger = LoggerFactory.getLogger(UserRegisterFilterApplicationService::class.java)
}
override suspend fun internalExecute(command: RegisterFilter, executor: CommandExecutor): Filter {
require(executor is UserDetailGettableCommandExecutor)
val filter = dev.usbharu.hideout.core.domain.model.filter.Filter.create(
FilterId(idGenerateService.generateId()),
UserDetailId(executor.userDetailId),
FilterName(command.filterName),
command.filterContext,
command.filterAction,
command.filterKeywords
.map {
FilterKeyword(
FilterKeywordId(idGenerateService.generateId()),
FilterKeywordKeyword(it.keyword),
it.filterMode
)
}.toSet()
)
filterRepository.save(filter)
return Filter.of(filter)
}
}

View File

@ -9,9 +9,9 @@ class Filter(
val id: FilterId,
val userDetailId: UserDetailId,
var name: FilterName,
val filterContext: List<FilterContext>,
val filterContext: Set<FilterContext>,
val filterAction: FilterAction,
filterKeywords: Set<FilterKeyword>
filterKeywords: Set<FilterKeyword>,
) {
var filterKeywords = filterKeywords
private set
@ -39,6 +39,17 @@ class Filter(
.toRegex()
}
fun reconstructWith(filterKeywords: Set<FilterKeyword>): Filter {
return Filter(
this.id,
this.userDetailId,
this.name,
this.filterContext,
this.filterAction,
filterKeywords
)
}
companion object {
fun isAllow(user: UserDetail, action: Action, resource: Filter): Boolean {
return when (action) {
@ -49,5 +60,23 @@ class Filter(
enum class Action {
SET_KEYWORDS
}
fun create(
id: FilterId,
userDetailId: UserDetailId,
name: FilterName,
filterContext: Set<FilterContext>,
filterAction: FilterAction,
filterKeywords: Set<FilterKeyword>,
): Filter {
return Filter(
id,
userDetailId,
name,
filterContext,
filterAction,
filterKeywords
)
}
}
}

View File

@ -3,4 +3,7 @@ package dev.usbharu.hideout.core.domain.model.filter
interface FilterRepository {
suspend fun save(filter: Filter): Filter
suspend fun delete(filter: Filter)
suspend fun findByFilterKeywordId(filterKeywordId: FilterKeywordId): Filter?
suspend fun findByFilterId(filterId: FilterId): Filter?
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.infrastructure.exposed
import dev.usbharu.hideout.core.domain.model.filter.*
import dev.usbharu.hideout.core.infrastructure.exposedrepository.FilterKeywords
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Filters
import org.jetbrains.exposed.sql.Query
import org.jetbrains.exposed.sql.ResultRow
import org.springframework.stereotype.Component
@Component
class FilterQueryMapper(private val filterResultRowMapper: ResultRowMapper<Filter>) : QueryMapper<Filter> {
override fun map(query: Query): List<Filter> {
return query
.groupBy { it[Filters.id] }
.map { it.value }
.map {
it
.first()
.let(filterResultRowMapper::map)
.apply {
reconstructWith(it.mapNotNull { resultRow: ResultRow ->
FilterKeyword(
FilterKeywordId(resultRow.getOrNull(FilterKeywords.id) ?: return@mapNotNull null),
FilterKeywordKeyword(
resultRow.getOrNull(FilterKeywords.keyword) ?: return@mapNotNull null
),
FilterMode.valueOf(resultRow.getOrNull(FilterKeywords.mode) ?: return@mapNotNull null)
)
}.toSet())
}
}
}
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.infrastructure.exposed
import dev.usbharu.hideout.core.domain.model.filter.*
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Filters
import org.jetbrains.exposed.sql.ResultRow
import org.springframework.stereotype.Component
@Component
class FilterResultRowMapper : ResultRowMapper<Filter> {
override fun map(resultRow: ResultRow): Filter = Filter(
FilterId(resultRow[Filters.id]),
UserDetailId(resultRow[Filters.userId]),
FilterName(resultRow[Filters.name]),
resultRow[Filters.context].split(",").filter { it.isNotEmpty() }.map { FilterContext.valueOf(it) }.toSet(),
FilterAction.valueOf(resultRow[Filters.filterAction]),
emptySet()
)
}

View File

@ -0,0 +1,98 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.infrastructure.exposedrepository
import dev.usbharu.hideout.core.domain.model.filter.Filter
import dev.usbharu.hideout.core.domain.model.filter.FilterId
import dev.usbharu.hideout.core.domain.model.filter.FilterKeywordId
import dev.usbharu.hideout.core.domain.model.filter.FilterRepository
import dev.usbharu.hideout.core.infrastructure.exposed.QueryMapper
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Repository
@Repository
class ExposedFilterRepository(private val filterQueryMapper: QueryMapper<Filter>) : FilterRepository,
AbstractRepository() {
override suspend fun save(filter: Filter): Filter = query {
Filters.upsert {
it[id] = filter.id.id
it[userId] = filter.userDetailId.id
it[name] = filter.name.name
it[context] = filter.filterContext.joinToString(",") { it.name }
it[filterAction] = filter.filterAction.name
}
FilterKeywords.deleteWhere {
filterId eq filter.id.id
}
FilterKeywords.batchUpsert(filter.filterKeywords) {
this[FilterKeywords.id] = it.id.id
this[FilterKeywords.filterId] = filter.id.id
this[FilterKeywords.keyword] = it.keyword.keyword
this[FilterKeywords.mode] = it.mode.name
}
filter
}
override suspend fun delete(filter: Filter): Unit = query {
FilterKeywords.deleteWhere { filterId eq filter.id.id }
Filters.deleteWhere { id eq filter.id.id }
}
override suspend fun findByFilterKeywordId(filterKeywordId: FilterKeywordId): Filter? {
val filterId = FilterKeywords
.selectAll()
.where { FilterKeywords.id eq filterKeywordId.id }
.firstOrNull()?.get(FilterKeywords.filterId) ?: return null
val where = Filters.selectAll().where { Filters.id eq filterId }
return filterQueryMapper.map(where).firstOrNull()
}
override suspend fun findByFilterId(filterId: FilterId): Filter? {
val where = Filters.selectAll().where { Filters.id eq filterId.id }
return filterQueryMapper.map(where).firstOrNull()
}
override val logger: Logger
get() = Companion.logger
companion object {
private val logger = LoggerFactory.getLogger(ExposedFilterRepository::class.java)
}
}
object Filters : Table("filters") {
val id = long("id")
val userId = long("user_id").references(UserDetails.id, ReferenceOption.CASCADE, ReferenceOption.CASCADE)
val name = varchar("name", 255)
val context = varchar("context", 500)
val filterAction = varchar("action", 255)
override val primaryKey: PrimaryKey = PrimaryKey(id)
}
object FilterKeywords : Table("filter_keywords") {
val id = long("id")
val filterId =
long("filter_id").references(Filters.id, onDelete = ReferenceOption.CASCADE, onUpdate = ReferenceOption.CASCADE)
val keyword = varchar("keyword", 1000)
val mode = varchar("mode", 100)
override val primaryKey: PrimaryKey = PrimaryKey(id)
}

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.mastodon.application.filter
data class DeleteFilterV1(val filterKeywordId: Long)

View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.mastodon.application.filter
import dev.usbharu.hideout.core.application.shared.AbstractApplicationService
import dev.usbharu.hideout.core.application.shared.CommandExecutor
import dev.usbharu.hideout.core.application.shared.Transaction
import dev.usbharu.hideout.core.domain.model.filter.FilterKeywordId
import dev.usbharu.hideout.core.domain.model.filter.FilterRepository
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
@Service
class DeleteFilterV1ApplicationService(private val filterRepository: FilterRepository, transaction: Transaction) :
AbstractApplicationService<DeleteFilterV1, Unit>(
transaction, logger
) {
companion object {
private val logger = LoggerFactory.getLogger(DeleteFilterV1ApplicationService::class.java)
}
override suspend fun internalExecute(command: DeleteFilterV1, executor: CommandExecutor) {
val filter = filterRepository.findByFilterKeywordId(FilterKeywordId(command.filterKeywordId))
?: throw Exception("Not Found")
filterRepository.delete(filter)
}
}

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.mastodon.application.filter
data class GetFilterV1(val filterKeywordId: Long)

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.mastodon.application.filter
import dev.usbharu.hideout.core.application.shared.AbstractApplicationService
import dev.usbharu.hideout.core.application.shared.CommandExecutor
import dev.usbharu.hideout.core.application.shared.Transaction
import dev.usbharu.hideout.core.domain.model.filter.FilterContext.*
import dev.usbharu.hideout.core.domain.model.filter.FilterKeywordId
import dev.usbharu.hideout.core.domain.model.filter.FilterMode
import dev.usbharu.hideout.core.domain.model.filter.FilterRepository
import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.V1Filter
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Repository
@Repository
class GetFilterV1ApplicationService(private val filterRepository: FilterRepository, transaction: Transaction) :
AbstractApplicationService<GetFilterV1, V1Filter>(
transaction, logger
) {
override suspend fun internalExecute(command: GetFilterV1, executor: CommandExecutor): V1Filter {
val filter = filterRepository.findByFilterKeywordId(FilterKeywordId(command.filterKeywordId))
?: throw Exception("Not Found")
val filterKeyword = filter.filterKeywords.find { it.id.id == command.filterKeywordId }
return V1Filter(
id = filter.id.id.toString(),
phrase = filterKeyword?.keyword?.keyword,
context = filter.filterContext.map {
when (it) {
home -> V1Filter.Context.home
notifications -> V1Filter.Context.notifications
public -> V1Filter.Context.public
thread -> V1Filter.Context.thread
account -> V1Filter.Context.account
}
},
expiresAt = null,
irreversible = false,
wholeWord = filterKeyword?.mode == FilterMode.WHOLE_WORD
)
}
companion object {
private val logger = LoggerFactory.getLogger(GetFilterV1ApplicationService::class.java)
}
}

View File

@ -16,21 +16,50 @@
package dev.usbharu.hideout.mastodon.interfaces.api
import dev.usbharu.hideout.core.application.filter.*
import dev.usbharu.hideout.core.domain.model.filter.FilterAction
import dev.usbharu.hideout.core.domain.model.filter.FilterContext
import dev.usbharu.hideout.core.domain.model.filter.FilterMode
import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.Oauth2CommandExecutorFactory
import dev.usbharu.hideout.mastodon.application.filter.DeleteFilterV1
import dev.usbharu.hideout.mastodon.application.filter.DeleteFilterV1ApplicationService
import dev.usbharu.hideout.mastodon.application.filter.GetFilterV1
import dev.usbharu.hideout.mastodon.application.filter.GetFilterV1ApplicationService
import dev.usbharu.hideout.mastodon.interfaces.api.generated.FilterApi
import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.*
import kotlinx.coroutines.flow.Flow
import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.Filter
import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.FilterKeyword
import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.FilterPostRequest.Context
import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.V1FilterPostRequest.Context.*
import org.springframework.http.ResponseEntity
import org.springframework.stereotype.Controller
@Controller
class SpringFilterApi : FilterApi {
class SpringFilterApi(
private val oauth2CommandExecutorFactory: Oauth2CommandExecutorFactory,
private val userRegisterFilterApplicationService: UserRegisterFilterApplicationService,
private val getFilterV1ApplicationService: GetFilterV1ApplicationService,
private val deleteFilterV1ApplicationService: DeleteFilterV1ApplicationService,
private val userDeleteFilterApplicationService: UserDeleteFilterApplicationService,
private val userGetFilterApplicationService: UserGetFilterApplicationService,
) : FilterApi {
override suspend fun apiV1FiltersIdDelete(id: String): ResponseEntity<Any> {
return super.apiV1FiltersIdDelete(id)
return ResponseEntity.ok(
deleteFilterV1ApplicationService.execute(
DeleteFilterV1(id.toLong()),
oauth2CommandExecutorFactory.getCommandExecutor()
)
)
}
override suspend fun apiV1FiltersIdGet(id: String): ResponseEntity<V1Filter> {
return super.apiV1FiltersIdGet(id)
return ResponseEntity.ok(
getFilterV1ApplicationService.execute(
GetFilterV1(id.toLong()),
oauth2CommandExecutorFactory.getCommandExecutor()
)
)
}
override suspend fun apiV1FiltersIdPut(
@ -45,7 +74,33 @@ class SpringFilterApi : FilterApi {
}
override suspend fun apiV1FiltersPost(v1FilterPostRequest: V1FilterPostRequest): ResponseEntity<V1Filter> {
return super.apiV1FiltersPost(v1FilterPostRequest)
val executor = oauth2CommandExecutorFactory.getCommandExecutor()
val filterMode = if (v1FilterPostRequest.wholeWord == true) {
FilterMode.WHOLE_WORD
} else {
FilterMode.NONE
}
val filterContext = v1FilterPostRequest.context.map {
when (it) {
home -> FilterContext.home
notifications -> FilterContext.notifications
public -> FilterContext.public
thread -> FilterContext.thread
account -> FilterContext.account
}
}.toSet()
val filter = userRegisterFilterApplicationService.execute(
RegisterFilter(
v1FilterPostRequest.phrase, filterContext, FilterAction.warn,
setOf(RegisterFilterKeyword(v1FilterPostRequest.phrase, filterMode))
), executor
)
return ResponseEntity.ok(
getFilterV1ApplicationService.execute(
GetFilterV1(filter.filterKeywords.first().id),
executor
)
)
}
override suspend fun apiV2FiltersFilterIdKeywordsPost(
@ -63,13 +118,50 @@ class SpringFilterApi : FilterApi {
}
override suspend fun apiV2FiltersIdDelete(id: String): ResponseEntity<Any> {
return super.apiV2FiltersIdDelete(id)
userDeleteFilterApplicationService.execute(
DeleteFilter(id.toLong()),
oauth2CommandExecutorFactory.getCommandExecutor()
)
return ResponseEntity.ok(Unit)
}
override suspend fun apiV2FiltersIdGet(id: String): ResponseEntity<Filter> {
return super.apiV2FiltersIdGet(id)
val filter = userGetFilterApplicationService.execute(
GetFilter(id.toLong()),
oauth2CommandExecutorFactory.getCommandExecutor()
)
return ResponseEntity.ok(
filter(filter)
)
}
private fun filter(filter: dev.usbharu.hideout.core.application.filter.Filter) = Filter(
id = filter.filterId.toString(),
title = filter.name,
context = filter.filterContext.map {
when (it) {
FilterContext.home -> Filter.Context.home
FilterContext.notifications -> Filter.Context.notifications
FilterContext.public -> Filter.Context.public
FilterContext.thread -> Filter.Context.thread
FilterContext.account -> Filter.Context.account
}
},
expiresAt = null,
filterAction = when (filter.filterAction) {
FilterAction.warn -> Filter.FilterAction.warn
FilterAction.hide -> Filter.FilterAction.hide
},
keywords = filter.filterKeywords.map {
FilterKeyword(
it.id.toString(),
it.keyword,
it.filterMode == FilterMode.WHOLE_WORD
)
}, statuses = null
)
override suspend fun apiV2FiltersIdPut(
id: String,
title: String?,
@ -99,14 +191,46 @@ class SpringFilterApi : FilterApi {
}
override suspend fun apiV2FiltersPost(filterPostRequest: FilterPostRequest): ResponseEntity<Filter> {
return super.apiV2FiltersPost(filterPostRequest)
val executor = oauth2CommandExecutorFactory.getCommandExecutor()
val filter = userRegisterFilterApplicationService.execute(
RegisterFilter(
filterName = filterPostRequest.title,
filterContext = filterPostRequest.context.map {
when (it) {
Context.home -> FilterContext.home
Context.notifications -> FilterContext.notifications
Context.public -> FilterContext.public
Context.thread -> FilterContext.thread
Context.account -> FilterContext.account
}
}.toSet(),
filterAction = when (filterPostRequest.filterAction) {
FilterPostRequest.FilterAction.warn -> FilterAction.warn
FilterPostRequest.FilterAction.hide -> FilterAction.hide
null -> FilterAction.warn
},
filterKeywords = filterPostRequest.keywordsAttributes.orEmpty().map {
RegisterFilterKeyword(
it.keyword,
if (it.regex == true) {
FilterMode.REGEX
} else if (it.wholeWord == true) {
FilterMode.WHOLE_WORD
} else {
FilterMode.NONE
}
)
}.toSet()
), executor
)
return ResponseEntity.ok(filter(filter))
}
override suspend fun apiV2FiltersStatusesIdDelete(id: String): ResponseEntity<Any> {
return super.apiV2FiltersStatusesIdDelete(id)
return ResponseEntity.notFound().build()
}
override suspend fun apiV2FiltersStatusesIdGet(id: String): ResponseEntity<FilterStatus> {
return super.apiV2FiltersStatusesIdGet(id)
return ResponseEntity.notFound().build()
}
}