mirror of https://github.com/usbharu/Hideout.git
feat: ミュートのMastodon互換APIを実装
This commit is contained in:
parent
01ae2268d5
commit
5cb014730e
|
@ -6,6 +6,9 @@ interface FilterRepository {
|
|||
suspend fun save(filter: Filter): Filter
|
||||
suspend fun findById(id: Long): Filter?
|
||||
|
||||
suspend fun findByUserIdAndId(userId: Long, id: Long): Filter?
|
||||
suspend fun findByUserIdAndType(userId: Long, types: List<FilterType>): List<Filter>
|
||||
suspend fun deleteById(id: Long)
|
||||
|
||||
suspend fun deleteByUserIdAndId(userId: Long, id: Long)
|
||||
}
|
|
@ -4,4 +4,7 @@ import dev.usbharu.hideout.core.domain.model.filter.FilterType
|
|||
|
||||
interface FilterQueryService {
|
||||
suspend fun findByUserIdAndType(userId: Long, types: List<FilterType>): List<FilterQueryModel>
|
||||
suspend fun findByUserId(userId: Long): List<FilterQueryModel>
|
||||
suspend fun findByUserIdAndId(userId: Long, id: Long): FilterQueryModel?
|
||||
suspend fun findByUserIdAndKeywordId(userId: Long, keywordId: Long): FilterQueryModel?
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
package dev.usbharu.hideout.core.service.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.FilterType
|
||||
import dev.usbharu.hideout.core.query.model.FilterQueryModel
|
||||
|
@ -8,12 +7,11 @@ import dev.usbharu.hideout.core.query.model.FilterQueryModel
|
|||
interface MuteService {
|
||||
suspend fun createFilter(
|
||||
title: String,
|
||||
name: String,
|
||||
context: List<FilterType>,
|
||||
action: FilterAction,
|
||||
keywords: List<FilterKeyword>,
|
||||
loginUser: Long
|
||||
): Filter
|
||||
): FilterQueryModel
|
||||
|
||||
suspend fun getFilters(userId: Long, types: List<FilterType> = emptyList()): List<FilterQueryModel>
|
||||
|
||||
|
|
|
@ -17,16 +17,15 @@ class MuteServiceImpl(
|
|||
) : MuteService {
|
||||
override suspend fun createFilter(
|
||||
title: String,
|
||||
name: String,
|
||||
context: List<FilterType>,
|
||||
action: FilterAction,
|
||||
keywords: List<FilterKeyword>,
|
||||
loginUser: Long
|
||||
): Filter {
|
||||
): FilterQueryModel {
|
||||
val filter = Filter(
|
||||
filterRepository.generateId(),
|
||||
loginUser,
|
||||
name,
|
||||
title,
|
||||
context,
|
||||
action
|
||||
)
|
||||
|
@ -42,7 +41,8 @@ class MuteServiceImpl(
|
|||
|
||||
filterKeywordRepository.saveAll(filterKeywordList)
|
||||
|
||||
return filterRepository.save(filter)
|
||||
val savedFilter = filterRepository.save(filter)
|
||||
return FilterQueryModel.of(savedFilter, filterKeywordList)
|
||||
}
|
||||
|
||||
override suspend fun getFilters(userId: Long, types: List<FilterType>): List<FilterQueryModel> =
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
package dev.usbharu.hideout.mastodon.interfaces.api.filter
|
||||
|
||||
import dev.usbharu.hideout.controller.mastodon.generated.FilterApi
|
||||
import dev.usbharu.hideout.domain.mastodon.model.generated.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.stereotype.Controller
|
||||
|
||||
@Controller
|
||||
class MastodonFilterApiController : FilterApi {
|
||||
|
||||
override suspend fun apiV1FiltersIdDelete(id: String): ResponseEntity<Any> {
|
||||
return super.apiV1FiltersIdDelete(id)
|
||||
}
|
||||
|
||||
override suspend fun apiV1FiltersIdGet(
|
||||
id: String
|
||||
): ResponseEntity<V1Filter> {
|
||||
return super.apiV1FiltersIdGet(id)
|
||||
}
|
||||
|
||||
override suspend fun apiV1FiltersIdPut(
|
||||
id: String,
|
||||
phrase: String?,
|
||||
context: List<String>?,
|
||||
irreversible: Boolean?,
|
||||
wholeWord: Boolean?,
|
||||
expiresIn: Int?
|
||||
): ResponseEntity<V1Filter> {
|
||||
return super.apiV1FiltersIdPut(id, phrase, context, irreversible, wholeWord, expiresIn)
|
||||
}
|
||||
|
||||
override suspend fun apiV1FiltersPost(v1FilterPostRequest: V1FilterPostRequest): ResponseEntity<V1Filter> {
|
||||
return super.apiV1FiltersPost(v1FilterPostRequest)
|
||||
}
|
||||
|
||||
override suspend fun apiV2FiltersFilterIdKeywordsPost(
|
||||
filterId: String,
|
||||
filterKeywordsPostRequest: FilterKeywordsPostRequest
|
||||
): ResponseEntity<FilterKeyword> {
|
||||
return super.apiV2FiltersFilterIdKeywordsPost(filterId, filterKeywordsPostRequest)
|
||||
}
|
||||
|
||||
override suspend fun apiV2FiltersFilterIdStatusesPost(
|
||||
filterId: String,
|
||||
filterStatusRequest: FilterStatusRequest
|
||||
): ResponseEntity<FilterStatus> {
|
||||
return super.apiV2FiltersFilterIdStatusesPost(filterId, filterStatusRequest)
|
||||
}
|
||||
|
||||
override suspend fun apiV2FiltersIdDelete(id: String): ResponseEntity<Any> {
|
||||
return super.apiV2FiltersIdDelete(id)
|
||||
}
|
||||
|
||||
override suspend fun apiV2FiltersIdGet(id: String): ResponseEntity<Filter> {
|
||||
return super.apiV2FiltersIdGet(id)
|
||||
}
|
||||
|
||||
override suspend fun apiV2FiltersIdPut(
|
||||
id: String,
|
||||
title: String?,
|
||||
context: List<String>?,
|
||||
filterAction: String?,
|
||||
expiresIn: Int?,
|
||||
keywordsAttributes: List<FilterPubRequestKeyword>?
|
||||
): ResponseEntity<Filter> {
|
||||
return super.apiV2FiltersIdPut(id, title, context, filterAction, expiresIn, keywordsAttributes)
|
||||
}
|
||||
|
||||
override suspend fun apiV2FiltersKeywordsIdDelete(id: String): ResponseEntity<Any> {
|
||||
return super.apiV2FiltersKeywordsIdDelete(id)
|
||||
}
|
||||
|
||||
override suspend fun apiV2FiltersKeywordsIdGet(id: String): ResponseEntity<FilterKeyword> {
|
||||
return super.apiV2FiltersKeywordsIdGet(id)
|
||||
}
|
||||
|
||||
override suspend fun apiV2FiltersKeywordsIdPut(
|
||||
id: String,
|
||||
keyword: String?,
|
||||
wholeWord: Boolean?,
|
||||
regex: Boolean?
|
||||
): ResponseEntity<FilterKeyword> {
|
||||
return super.apiV2FiltersKeywordsIdPut(id, keyword, wholeWord, regex)
|
||||
}
|
||||
|
||||
override suspend fun apiV2FiltersPost(filterPostRequest: FilterPostRequest): ResponseEntity<Filter> {
|
||||
return super.apiV2FiltersPost(filterPostRequest)
|
||||
}
|
||||
|
||||
override suspend fun apiV2FiltersStatusesIdDelete(id: String): ResponseEntity<Any> {
|
||||
return super.apiV2FiltersStatusesIdDelete(id)
|
||||
}
|
||||
|
||||
override suspend fun apiV2FiltersStatusesIdGet(id: String): ResponseEntity<FilterStatus> {
|
||||
return super.apiV2FiltersStatusesIdGet(id)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,288 @@
|
|||
package dev.usbharu.hideout.mastodon.service.filter
|
||||
|
||||
import dev.usbharu.hideout.core.domain.model.filter.FilterAction.hide
|
||||
import dev.usbharu.hideout.core.domain.model.filter.FilterAction.warn
|
||||
import dev.usbharu.hideout.core.domain.model.filter.FilterMode
|
||||
import dev.usbharu.hideout.core.domain.model.filter.FilterRepository
|
||||
import dev.usbharu.hideout.core.domain.model.filter.FilterType.*
|
||||
import dev.usbharu.hideout.core.domain.model.filterkeyword.FilterKeywordRepository
|
||||
import dev.usbharu.hideout.core.query.model.FilterQueryModel
|
||||
import dev.usbharu.hideout.core.query.model.FilterQueryService
|
||||
import dev.usbharu.hideout.core.service.filter.MuteService
|
||||
import dev.usbharu.hideout.domain.mastodon.model.generated.*
|
||||
import dev.usbharu.hideout.domain.mastodon.model.generated.FilterPostRequest.FilterAction
|
||||
import dev.usbharu.hideout.domain.mastodon.model.generated.V1Filter.Context
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
interface MastodonFilterApiService {
|
||||
fun v1Filters(userId: Long): Flow<V1Filter>
|
||||
|
||||
suspend fun deleteV1FilterById(userId: Long, id: Long)
|
||||
|
||||
suspend fun getV1FilterById(userId: Long, id: Long): V1Filter?
|
||||
|
||||
suspend fun createByV1Filter(userId: Long, v1FilterRequest: V1FilterPostRequest): V1Filter
|
||||
|
||||
fun filterKeywords(userId: Long, filterId: Long): Flow<FilterKeyword>
|
||||
|
||||
suspend fun addKeyword(userId: Long, filterId: Long, keyword: FilterKeywordsPostRequest): FilterKeyword
|
||||
|
||||
fun filterStatuses(userId: Long, filterId: Long): Flow<FilterStatus>
|
||||
|
||||
suspend fun addFilterStatus(userId: Long, filterId: Long, filterStatusRequest: FilterStatusRequest)
|
||||
|
||||
fun filters(userId: Long): Flow<Filter>
|
||||
|
||||
suspend fun deleteById(userId: Long, filterId: Long)
|
||||
|
||||
suspend fun getById(userId: Long, filterId: Long): Filter?
|
||||
|
||||
suspend fun deleteKeyword(userId: Long, keywordId: Long)
|
||||
|
||||
suspend fun getKeywordById(userId: Long, keywordId: Long): FilterKeyword?
|
||||
|
||||
suspend fun createFilter(userId: Long, filterPostRequest: FilterPostRequest): Filter
|
||||
|
||||
suspend fun deleteFilterStatusById(userId: Long, filterPostsId: Long)
|
||||
|
||||
suspend fun getFilterStatusById(userId: Long, filterPostsId: Long): FilterStatus?
|
||||
}
|
||||
|
||||
@Service
|
||||
class MastodonFilterApiServiceImpl(
|
||||
private val muteService: MuteService,
|
||||
private val filterQueryService: FilterQueryService,
|
||||
private val filterRepository: FilterRepository,
|
||||
private val filterKeywordRepository: FilterKeywordRepository
|
||||
) : MastodonFilterApiService {
|
||||
override fun v1Filters(userId: Long): Flow<V1Filter> {
|
||||
return runBlocking { filterQueryService.findByUserId(userId) }.flatMap { filterQueryModel ->
|
||||
filterQueryModel.keywords.map {
|
||||
V1Filter(
|
||||
id = it.id.toString(),
|
||||
phrase = it.keyword,
|
||||
context = filterQueryModel.context.map {
|
||||
when (it) {
|
||||
home -> Context.home
|
||||
notifications -> Context.notifications
|
||||
public -> Context.public
|
||||
thread -> Context.thread
|
||||
account -> Context.account
|
||||
}
|
||||
},
|
||||
expiresAt = null,
|
||||
irreversible = false,
|
||||
wholeWord = (it.mode != FilterMode.WHOLE_WORD).not()
|
||||
)
|
||||
}
|
||||
}.asFlow()
|
||||
}
|
||||
|
||||
override suspend fun deleteV1FilterById(userId: Long, id: Long) {
|
||||
val keywordId = filterQueryService.findByUserIdAndKeywordId(userId, id)?.keywords?.singleOrNull()?.id ?: return
|
||||
|
||||
filterKeywordRepository.deleteById(keywordId)
|
||||
}
|
||||
|
||||
override suspend fun getV1FilterById(userId: Long, id: Long): V1Filter? {
|
||||
val filterQueryModel = filterQueryService.findByUserIdAndKeywordId(userId, id) ?: return null
|
||||
|
||||
val filterKeyword = filterQueryModel.keywords.firstOrNull() ?: return null
|
||||
|
||||
return v1Filter(filterQueryModel, filterKeyword)
|
||||
}
|
||||
|
||||
private fun v1Filter(
|
||||
filterQueryModel: FilterQueryModel,
|
||||
filterKeyword: dev.usbharu.hideout.core.domain.model.filterkeyword.FilterKeyword
|
||||
) = V1Filter(
|
||||
id = filterQueryModel.id.toString(),
|
||||
phrase = filterKeyword.keyword,
|
||||
context = filterQueryModel.context.map {
|
||||
when (it) {
|
||||
home -> Context.home
|
||||
notifications -> Context.notifications
|
||||
public -> Context.public
|
||||
thread -> Context.thread
|
||||
account -> Context.account
|
||||
}
|
||||
},
|
||||
expiresAt = null,
|
||||
irreversible = false,
|
||||
wholeWord = filterKeyword.mode == FilterMode.WHOLE_WORD
|
||||
)
|
||||
|
||||
override suspend fun createByV1Filter(userId: Long, v1FilterRequest: V1FilterPostRequest): V1Filter {
|
||||
val createFilter = muteService.createFilter(
|
||||
title = v1FilterRequest.phrase,
|
||||
context = v1FilterRequest.context.map {
|
||||
when (it) {
|
||||
V1FilterPostRequest.Context.home -> home
|
||||
V1FilterPostRequest.Context.notifications -> notifications
|
||||
V1FilterPostRequest.Context.public -> public
|
||||
V1FilterPostRequest.Context.thread -> thread
|
||||
V1FilterPostRequest.Context.account -> account
|
||||
}
|
||||
},
|
||||
action = warn,
|
||||
keywords = listOf(
|
||||
dev.usbharu.hideout.core.service.filter.FilterKeyword(
|
||||
v1FilterRequest.phrase,
|
||||
if (v1FilterRequest.wholeWord == true) {
|
||||
FilterMode.WHOLE_WORD
|
||||
} else {
|
||||
FilterMode.NONE
|
||||
}
|
||||
)
|
||||
),
|
||||
loginUser = userId
|
||||
)
|
||||
|
||||
return v1Filter(createFilter, createFilter.keywords.first())
|
||||
}
|
||||
|
||||
override fun filterKeywords(userId: Long, filterId: Long): Flow<FilterKeyword> =
|
||||
runBlocking { filterQueryService.findByUserIdAndId(userId, filterId) }
|
||||
?.keywords
|
||||
?.map {
|
||||
toFilterKeyword(
|
||||
it
|
||||
)
|
||||
}
|
||||
.orEmpty()
|
||||
.asFlow()
|
||||
|
||||
override suspend fun addKeyword(userId: Long, filterId: Long, keyword: FilterKeywordsPostRequest): FilterKeyword {
|
||||
val id = filterQueryService.findByUserIdAndId(userId, filterId)?.id
|
||||
?: throw IllegalArgumentException("filter not found.")
|
||||
|
||||
val filterKeyword = filterKeywordRepository.save(
|
||||
dev.usbharu.hideout.core.domain.model.filterkeyword.FilterKeyword(
|
||||
id = filterKeywordRepository.generateId(),
|
||||
filterId = id,
|
||||
keyword = keyword.keyword,
|
||||
mode = if (keyword.regex == true) {
|
||||
FilterMode.REGEX
|
||||
} else if (keyword.wholeWord == true) {
|
||||
FilterMode.WHOLE_WORD
|
||||
} else {
|
||||
FilterMode.NONE
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
return toFilterKeyword(filterKeyword)
|
||||
}
|
||||
|
||||
override fun filterStatuses(userId: Long, filterId: Long): Flow<FilterStatus> {
|
||||
return emptyFlow()
|
||||
}
|
||||
|
||||
override suspend fun addFilterStatus(userId: Long, filterId: Long, filterStatusRequest: FilterStatusRequest) {
|
||||
return
|
||||
}
|
||||
|
||||
override fun filters(userId: Long): Flow<Filter> {
|
||||
return runBlocking { filterQueryService.findByUserId(userId) }.map { filterQueryModel ->
|
||||
toFilter(filterQueryModel)
|
||||
}.asFlow()
|
||||
}
|
||||
|
||||
private fun toFilter(filterQueryModel: FilterQueryModel) = Filter(
|
||||
id = filterQueryModel.id.toString(),
|
||||
title = filterQueryModel.name,
|
||||
context = filterQueryModel.context.map {
|
||||
when (it) {
|
||||
home -> Filter.Context.home
|
||||
notifications -> Filter.Context.notifications
|
||||
public -> Filter.Context.public
|
||||
thread -> Filter.Context.thread
|
||||
account -> Filter.Context.account
|
||||
}
|
||||
},
|
||||
expiresAt = null,
|
||||
filterAction = when (filterQueryModel.filterAction) {
|
||||
warn -> Filter.FilterAction.warn
|
||||
hide -> Filter.FilterAction.hide
|
||||
},
|
||||
keywords = filterQueryModel.keywords.map {
|
||||
toFilterKeyword(it)
|
||||
},
|
||||
statuses = null
|
||||
)
|
||||
|
||||
private fun toFilterKeyword(it: dev.usbharu.hideout.core.domain.model.filterkeyword.FilterKeyword) = FilterKeyword(
|
||||
it.id.toString(),
|
||||
it.keyword,
|
||||
it.mode == FilterMode.WHOLE_WORD
|
||||
)
|
||||
|
||||
override suspend fun deleteById(userId: Long, filterId: Long) {
|
||||
filterRepository.deleteByUserIdAndId(userId, filterId)
|
||||
}
|
||||
|
||||
override suspend fun getById(userId: Long, filterId: Long): Filter? =
|
||||
filterQueryService.findByUserIdAndId(userId, filterId)?.let { toFilter(it) }
|
||||
|
||||
override suspend fun deleteKeyword(userId: Long, keywordId: Long) {
|
||||
val id = filterQueryService.findByUserIdAndKeywordId(userId, keywordId)?.keywords?.singleOrNull()?.id ?: return
|
||||
|
||||
filterKeywordRepository.deleteById(id)
|
||||
}
|
||||
|
||||
override suspend fun getKeywordById(userId: Long, keywordId: Long): FilterKeyword? {
|
||||
return filterQueryService
|
||||
.findByUserIdAndKeywordId(userId, keywordId)
|
||||
?.keywords
|
||||
?.firstOrNull()
|
||||
?.let { toFilterKeyword(it) }
|
||||
}
|
||||
|
||||
override suspend fun createFilter(userId: Long, filterPostRequest: FilterPostRequest): Filter {
|
||||
val keywords = filterPostRequest.keywordsAttributes.orEmpty().map {
|
||||
dev.usbharu.hideout.core.service.filter.FilterKeyword(
|
||||
it.keyword,
|
||||
if (it.regex == true) {
|
||||
FilterMode.REGEX
|
||||
} else if (it.wholeWord == true) {
|
||||
FilterMode.WHOLE_WORD
|
||||
} else {
|
||||
FilterMode.NONE
|
||||
}
|
||||
)
|
||||
}
|
||||
return toFilter(
|
||||
muteService.createFilter(
|
||||
title = filterPostRequest.title,
|
||||
context = filterPostRequest.context.map {
|
||||
when (it) {
|
||||
FilterPostRequest.Context.home -> home
|
||||
FilterPostRequest.Context.notifications -> notifications
|
||||
FilterPostRequest.Context.public -> public
|
||||
FilterPostRequest.Context.thread -> thread
|
||||
FilterPostRequest.Context.account -> account
|
||||
}
|
||||
},
|
||||
action = when (filterPostRequest.filterAction) {
|
||||
FilterAction.warn -> warn
|
||||
FilterAction.hide -> warn
|
||||
null -> warn
|
||||
},
|
||||
keywords = keywords,
|
||||
loginUser = userId
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun deleteFilterStatusById(userId: Long, filterPostsId: Long) {
|
||||
return
|
||||
}
|
||||
|
||||
override suspend fun getFilterStatusById(userId: Long, filterPostsId: Long): FilterStatus? {
|
||||
return null
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue