mirror of https://github.com/usbharu/Hideout.git
refactor: 不要な宣言等を削除
This commit is contained in:
parent
4542fdf68b
commit
34d8eabea1
|
@ -1,5 +1,7 @@
|
||||||
package dev.usbharu.hideout.activitypub.domain.exception
|
package dev.usbharu.hideout.activitypub.domain.exception
|
||||||
|
|
||||||
|
import java.io.Serial
|
||||||
|
|
||||||
class FailedProcessException : RuntimeException {
|
class FailedProcessException : RuntimeException {
|
||||||
constructor() : super()
|
constructor() : super()
|
||||||
constructor(message: String?) : super(message)
|
constructor(message: String?) : super(message)
|
||||||
|
@ -11,4 +13,9 @@ class FailedProcessException : RuntimeException {
|
||||||
enableSuppression,
|
enableSuppression,
|
||||||
writableStackTrace
|
writableStackTrace
|
||||||
)
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Serial
|
||||||
|
private const val serialVersionUID: Long = -1305337651143409144L
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
package dev.usbharu.hideout.activitypub.domain.exception
|
package dev.usbharu.hideout.activitypub.domain.exception
|
||||||
|
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
||||||
|
import java.io.Serial
|
||||||
|
|
||||||
class FailedToGetActivityPubResourceException : FailedToGetResourcesException {
|
class FailedToGetActivityPubResourceException : FailedToGetResourcesException {
|
||||||
constructor() : super()
|
constructor() : super()
|
||||||
constructor(s: String?) : super(s)
|
constructor(s: String?) : super(s)
|
||||||
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||||
constructor(cause: Throwable?) : super(cause)
|
constructor(cause: Throwable?) : super(cause)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Serial
|
||||||
|
private const val serialVersionUID: Long = 6420233106776818052L
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package dev.usbharu.hideout.activitypub.domain.exception
|
package dev.usbharu.hideout.activitypub.domain.exception
|
||||||
|
|
||||||
|
import java.io.Serial
|
||||||
|
|
||||||
class HttpSignatureUnauthorizedException : RuntimeException {
|
class HttpSignatureUnauthorizedException : RuntimeException {
|
||||||
constructor() : super()
|
constructor() : super()
|
||||||
constructor(message: String?) : super(message)
|
constructor(message: String?) : super(message)
|
||||||
|
@ -11,4 +13,9 @@ class HttpSignatureUnauthorizedException : RuntimeException {
|
||||||
enableSuppression,
|
enableSuppression,
|
||||||
writableStackTrace
|
writableStackTrace
|
||||||
)
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Serial
|
||||||
|
private const val serialVersionUID: Long = -6449793151674654501L
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,8 @@ open class Document(
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
var result = super.hashCode()
|
var result = super.hashCode()
|
||||||
result = 31 * result + (mediaType?.hashCode() ?: 0)
|
result = 31 * result + mediaType.hashCode()
|
||||||
result = 31 * result + (url?.hashCode() ?: 0)
|
result = 31 * result + url.hashCode()
|
||||||
result = 31 * result + name.hashCode()
|
result = 31 * result + name.hashCode()
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,8 @@ open class Emoji(
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
var result = super.hashCode()
|
var result = super.hashCode()
|
||||||
result = 31 * result + (updated?.hashCode() ?: 0)
|
result = 31 * result + updated.hashCode()
|
||||||
result = 31 * result + (icon?.hashCode() ?: 0)
|
result = 31 * result + icon.hashCode()
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ open class Follow(
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
var result = super.hashCode()
|
var result = super.hashCode()
|
||||||
result = 31 * result + (`object`?.hashCode() ?: 0)
|
result = 31 * result + `object`.hashCode()
|
||||||
result = 31 * result + actor.hashCode()
|
result = 31 * result + actor.hashCode()
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,8 @@ open class Image(
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
var result = super.hashCode()
|
var result = super.hashCode()
|
||||||
result = 31 * result + (mediaType?.hashCode() ?: 0)
|
result = 31 * result + mediaType.hashCode()
|
||||||
result = 31 * result + (url?.hashCode() ?: 0)
|
result = 31 * result + url.hashCode()
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,8 @@ open class Key(
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
var result = super.hashCode()
|
var result = super.hashCode()
|
||||||
result = 31 * result + (owner?.hashCode() ?: 0)
|
result = 31 * result + owner.hashCode()
|
||||||
result = 31 * result + (publicKeyPem?.hashCode() ?: 0)
|
result = 31 * result + publicKeyPem.hashCode()
|
||||||
result = 31 * result + id.hashCode()
|
result = 31 * result + id.hashCode()
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,18 @@ constructor(
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String =
|
override fun toString(): String {
|
||||||
"Note(id='$id', attributedTo='$attributedTo', content='$content', published='$published', to=$to, cc=$cc, sensitive=$sensitive, inReplyTo=$inReplyTo, attachment=$attachment) ${super.toString()}"
|
return "Note(" +
|
||||||
|
"id='$id', " +
|
||||||
|
"attributedTo='$attributedTo', " +
|
||||||
|
"content='$content', " +
|
||||||
|
"published='$published', " +
|
||||||
|
"to=$to, " +
|
||||||
|
"cc=$cc, " +
|
||||||
|
"sensitive=$sensitive, " +
|
||||||
|
"inReplyTo=$inReplyTo, " +
|
||||||
|
"attachment=$attachment" +
|
||||||
|
")" +
|
||||||
|
" ${super.toString()}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,9 +41,9 @@ constructor(
|
||||||
var result = super.hashCode()
|
var result = super.hashCode()
|
||||||
result = 31 * result + (preferredUsername?.hashCode() ?: 0)
|
result = 31 * result + (preferredUsername?.hashCode() ?: 0)
|
||||||
result = 31 * result + (summary?.hashCode() ?: 0)
|
result = 31 * result + (summary?.hashCode() ?: 0)
|
||||||
result = 31 * result + (inbox?.hashCode() ?: 0)
|
result = 31 * result + inbox.hashCode()
|
||||||
result = 31 * result + (outbox?.hashCode() ?: 0)
|
result = 31 * result + outbox.hashCode()
|
||||||
result = 31 * result + (url?.hashCode() ?: 0)
|
result = 31 * result + url.hashCode()
|
||||||
result = 31 * result + (icon?.hashCode() ?: 0)
|
result = 31 * result + (icon?.hashCode() ?: 0)
|
||||||
result = 31 * result + (publicKey?.hashCode() ?: 0)
|
result = 31 * result + (publicKey?.hashCode() ?: 0)
|
||||||
result = 31 * result + endpoints.hashCode()
|
result = 31 * result + endpoints.hashCode()
|
||||||
|
|
|
@ -12,7 +12,7 @@ import dev.usbharu.hideout.core.query.UserQueryService
|
||||||
import dev.usbharu.hideout.core.service.user.UserService
|
import dev.usbharu.hideout.core.service.user.UserService
|
||||||
|
|
||||||
class ApAcceptProcessor(
|
class ApAcceptProcessor(
|
||||||
private val transaction: Transaction,
|
transaction: Transaction,
|
||||||
private val userQueryService: UserQueryService,
|
private val userQueryService: UserQueryService,
|
||||||
private val followerQueryService: FollowerQueryService,
|
private val followerQueryService: FollowerQueryService,
|
||||||
private val userService: UserService
|
private val userService: UserService
|
||||||
|
@ -23,14 +23,14 @@ class ApAcceptProcessor(
|
||||||
val value = activity.activity.`object` ?: throw IllegalActivityPubObjectException("object is null")
|
val value = activity.activity.`object` ?: throw IllegalActivityPubObjectException("object is null")
|
||||||
|
|
||||||
if (value.type.contains("Follow").not()) {
|
if (value.type.contains("Follow").not()) {
|
||||||
logger.warn("FAILED Activity type is not Follow.")
|
logger.warn("FAILED Activity type isn't Follow.")
|
||||||
throw IllegalActivityPubObjectException("Invalid type ${value.type}")
|
throw IllegalActivityPubObjectException("Invalid type ${value.type}")
|
||||||
}
|
}
|
||||||
|
|
||||||
val follow = value as Follow
|
val follow = value as Follow
|
||||||
|
|
||||||
val userUrl = follow.`object` ?: throw IllegalActivityPubObjectException("object is null")
|
val userUrl = follow.`object`
|
||||||
val followerUrl = follow.actor ?: throw IllegalActivityPubObjectException("actor is null")
|
val followerUrl = follow.actor
|
||||||
|
|
||||||
val user = userQueryService.findByUrl(userUrl)
|
val user = userQueryService.findByUrl(userUrl)
|
||||||
val follower = userQueryService.findByUrl(followerUrl)
|
val follower = userQueryService.findByUrl(followerUrl)
|
||||||
|
|
|
@ -11,7 +11,7 @@ import org.springframework.stereotype.Service
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class CreateActivityProcessor(transaction: Transaction, private val apNoteService: APNoteService) :
|
class CreateActivityProcessor(transaction: Transaction, private val apNoteService: APNoteService) :
|
||||||
AbstractActivityPubProcessor<Create>(transaction, false) {
|
AbstractActivityPubProcessor<Create>(transaction) {
|
||||||
override suspend fun internalProcess(activity: ActivityPubProcessContext<Create>) {
|
override suspend fun internalProcess(activity: ActivityPubProcessContext<Create>) {
|
||||||
apNoteService.fetchNote(activity.activity.`object` as Note)
|
apNoteService.fetchNote(activity.activity.`object` as Note)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package dev.usbharu.hideout.activitypub.service.activity.follow
|
package dev.usbharu.hideout.activitypub.service.activity.follow
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import dev.usbharu.hideout.activitypub.domain.exception.IllegalActivityPubObjectException
|
|
||||||
import dev.usbharu.hideout.activitypub.domain.model.Follow
|
import dev.usbharu.hideout.activitypub.domain.model.Follow
|
||||||
import dev.usbharu.hideout.activitypub.service.common.AbstractActivityPubProcessor
|
import dev.usbharu.hideout.activitypub.service.common.AbstractActivityPubProcessor
|
||||||
import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessContext
|
import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessContext
|
||||||
|
@ -22,9 +21,9 @@ class APFollowProcessor(
|
||||||
|
|
||||||
// inboxをジョブキューに乗せているので既に不要だが、フォロー承認制アカウントを実装する際に必要なので残す
|
// inboxをジョブキューに乗せているので既に不要だが、フォロー承認制アカウントを実装する際に必要なので残す
|
||||||
val jobProps = ReceiveFollowJobParam(
|
val jobProps = ReceiveFollowJobParam(
|
||||||
activity.activity.actor ?: throw IllegalActivityPubObjectException("actor is null"),
|
activity.activity.actor,
|
||||||
objectMapper.writeValueAsString(activity.activity),
|
objectMapper.writeValueAsString(activity.activity),
|
||||||
activity.activity.`object` ?: throw IllegalActivityPubObjectException("object is null")
|
activity.activity.`object`
|
||||||
)
|
)
|
||||||
jobQueueParentService.scheduleTypeSafe(ReceiveFollowJob, jobProps)
|
jobQueueParentService.scheduleTypeSafe(ReceiveFollowJob, jobProps)
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ class APReceiveFollowJobProcessor(
|
||||||
|
|
||||||
val signer = userQueryService.findByUrl(param.targetActor)
|
val signer = userQueryService.findByUrl(param.targetActor)
|
||||||
|
|
||||||
val urlString = person.inbox ?: throw IllegalArgumentException("inbox is not found.")
|
val urlString = person.inbox
|
||||||
|
|
||||||
apRequestService.apPost(
|
apRequestService.apPost(
|
||||||
url = urlString,
|
url = urlString,
|
||||||
|
@ -47,7 +47,7 @@ class APReceiveFollowJobProcessor(
|
||||||
|
|
||||||
val targetEntity = userQueryService.findByUrl(param.targetActor)
|
val targetEntity = userQueryService.findByUrl(param.targetActor)
|
||||||
val followActorEntity =
|
val followActorEntity =
|
||||||
userQueryService.findByUrl(follow.actor ?: throw IllegalArgumentException("actor is null"))
|
userQueryService.findByUrl(follow.actor)
|
||||||
|
|
||||||
userService.followRequest(targetEntity.id, followActorEntity.id)
|
userService.followRequest(targetEntity.id, followActorEntity.id)
|
||||||
logger.info("SUCCESS Follow from: {} to: {}", param.targetActor, param.actor)
|
logger.info("SUCCESS Follow from: {} to: {}", param.targetActor, param.actor)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package dev.usbharu.hideout.activitypub.service.activity.like
|
package dev.usbharu.hideout.activitypub.service.activity.like
|
||||||
|
|
||||||
import dev.usbharu.hideout.activitypub.domain.exception.FailedToGetActivityPubResourceException
|
import dev.usbharu.hideout.activitypub.domain.exception.FailedToGetActivityPubResourceException
|
||||||
import dev.usbharu.hideout.activitypub.domain.exception.IllegalActivityPubObjectException
|
|
||||||
import dev.usbharu.hideout.activitypub.domain.model.Like
|
import dev.usbharu.hideout.activitypub.domain.model.Like
|
||||||
import dev.usbharu.hideout.activitypub.service.common.AbstractActivityPubProcessor
|
import dev.usbharu.hideout.activitypub.service.common.AbstractActivityPubProcessor
|
||||||
import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessContext
|
import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessContext
|
||||||
|
@ -21,10 +20,10 @@ class APLikeProcessor(
|
||||||
) :
|
) :
|
||||||
AbstractActivityPubProcessor<Like>(transaction) {
|
AbstractActivityPubProcessor<Like>(transaction) {
|
||||||
override suspend fun internalProcess(activity: ActivityPubProcessContext<Like>) {
|
override suspend fun internalProcess(activity: ActivityPubProcessContext<Like>) {
|
||||||
val actor = activity.activity.actor ?: throw IllegalActivityPubObjectException("actor is null")
|
val actor = activity.activity.actor
|
||||||
val content = activity.activity.content ?: throw IllegalActivityPubObjectException("content is null")
|
val content = activity.activity.content
|
||||||
|
|
||||||
val target = activity.activity.`object` ?: throw IllegalActivityPubObjectException("object is null")
|
val target = activity.activity.`object`
|
||||||
|
|
||||||
val personWithEntity = apUserService.fetchPersonWithEntity(actor)
|
val personWithEntity = apUserService.fetchPersonWithEntity(actor)
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ class APUndoProcessor(
|
||||||
}
|
}
|
||||||
|
|
||||||
val type =
|
val type =
|
||||||
undo.`object`?.type.orEmpty()
|
undo.`object`.type.orEmpty()
|
||||||
.firstOrNull { it == "Block" || it == "Follow" || it == "Like" || it == "Announce" || it == "Accept" }
|
.firstOrNull { it == "Block" || it == "Follow" || it == "Like" || it == "Announce" || it == "Accept" }
|
||||||
?: return
|
?: return
|
||||||
|
|
||||||
|
@ -35,9 +35,9 @@ class APUndoProcessor(
|
||||||
if (follow.`object` == null) {
|
if (follow.`object` == null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
apUserService.fetchPerson(undo.actor!!, follow.`object`)
|
apUserService.fetchPerson(undo.actor, follow.`object`)
|
||||||
val follower = userQueryService.findByUrl(undo.actor!!)
|
val follower = userQueryService.findByUrl(undo.actor)
|
||||||
val target = userQueryService.findByUrl(follow.`object`!!)
|
val target = userQueryService.findByUrl(follow.`object`)
|
||||||
userService.unfollow(target.id, follower.id)
|
userService.unfollow(target.id, follower.id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ class APRequestServiceImpl(
|
||||||
url: String
|
url: String
|
||||||
): HttpResponse {
|
): HttpResponse {
|
||||||
val headers = headers {
|
val headers = headers {
|
||||||
append("Accept", ContentType.Application.Activity)
|
append("Accept", Activity)
|
||||||
append("Date", date)
|
append("Date", date)
|
||||||
append("Host", u.host)
|
append("Host", u.host)
|
||||||
}
|
}
|
||||||
|
@ -87,13 +87,13 @@ class APRequestServiceImpl(
|
||||||
remove("Host")
|
remove("Host")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
contentType(ContentType.Application.Activity)
|
contentType(Activity)
|
||||||
}
|
}
|
||||||
return httpResponse
|
return httpResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun apGetNotSign(url: String, date: String?) = httpClient.get(url) {
|
private suspend fun apGetNotSign(url: String, date: String?) = httpClient.get(url) {
|
||||||
header("Accept", ContentType.Application.Activity)
|
header("Accept", Activity)
|
||||||
header("Date", date)
|
header("Date", date)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,12 +153,12 @@ class APRequestServiceImpl(
|
||||||
digest: String,
|
digest: String,
|
||||||
requestBody: String?
|
requestBody: String?
|
||||||
) = httpClient.post(url) {
|
) = httpClient.post(url) {
|
||||||
accept(ContentType.Application.Activity)
|
accept(Activity)
|
||||||
header("Date", date)
|
header("Date", date)
|
||||||
header("Digest", "sha-256=$digest")
|
header("Digest", "sha-256=$digest")
|
||||||
if (requestBody != null) {
|
if (requestBody != null) {
|
||||||
setBody(requestBody)
|
setBody(requestBody)
|
||||||
contentType(ContentType.Application.Activity)
|
contentType(Activity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ class APRequestServiceImpl(
|
||||||
requestBody: String?
|
requestBody: String?
|
||||||
): HttpResponse {
|
): HttpResponse {
|
||||||
val headers = headers {
|
val headers = headers {
|
||||||
append("Accept", ContentType.Application.Activity)
|
append("Accept", Activity)
|
||||||
append("Date", date)
|
append("Date", date)
|
||||||
append("Host", u.host)
|
append("Host", u.host)
|
||||||
append("Digest", "sha-256=$digest")
|
append("Digest", "sha-256=$digest")
|
||||||
|
@ -196,7 +196,7 @@ class APRequestServiceImpl(
|
||||||
remove("Host")
|
remove("Host")
|
||||||
}
|
}
|
||||||
setBody(requestBody)
|
setBody(requestBody)
|
||||||
contentType(ContentType.Application.Activity)
|
contentType(Activity)
|
||||||
}
|
}
|
||||||
return httpResponse
|
return httpResponse
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,14 @@ import dev.usbharu.hideout.activitypub.domain.exception.FailedProcessException
|
||||||
import dev.usbharu.hideout.activitypub.domain.exception.HttpSignatureUnauthorizedException
|
import dev.usbharu.hideout.activitypub.domain.exception.HttpSignatureUnauthorizedException
|
||||||
import dev.usbharu.hideout.activitypub.domain.model.objects.Object
|
import dev.usbharu.hideout.activitypub.domain.model.objects.Object
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
abstract class AbstractActivityPubProcessor<T : Object>(
|
abstract class AbstractActivityPubProcessor<T : Object>(
|
||||||
private val transaction: Transaction,
|
private val transaction: Transaction,
|
||||||
private val allowUnauthorized: Boolean = false
|
private val allowUnauthorized: Boolean = false
|
||||||
) : ActivityPubProcessor<T> {
|
) : ActivityPubProcessor<T> {
|
||||||
protected val logger = LoggerFactory.getLogger(this::class.java)
|
protected val logger: Logger = LoggerFactory.getLogger(this::class.java)
|
||||||
|
|
||||||
override suspend fun process(activity: ActivityPubProcessContext<T>) {
|
override suspend fun process(activity: ActivityPubProcessContext<T>) {
|
||||||
if (activity.isAuthorized.not() && allowUnauthorized.not()) {
|
if (activity.isAuthorized.not() && allowUnauthorized.not()) {
|
||||||
|
|
|
@ -90,7 +90,7 @@ class APNoteServiceImpl(
|
||||||
requireNotNull(note.id) { "id is null" }
|
requireNotNull(note.id) { "id is null" }
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
noteQueryService.findByApid(note.id!!).first
|
noteQueryService.findByApid(note.id).first
|
||||||
} catch (_: FailedToGetResourcesException) {
|
} catch (_: FailedToGetResourcesException) {
|
||||||
saveNote(note, targetActor, url)
|
saveNote(note, targetActor, url)
|
||||||
}
|
}
|
||||||
|
@ -127,9 +127,9 @@ class APNoteServiceImpl(
|
||||||
.map {
|
.map {
|
||||||
mediaService.uploadRemoteMedia(
|
mediaService.uploadRemoteMedia(
|
||||||
RemoteMedia(
|
RemoteMedia(
|
||||||
(it.name ?: it.url)!!,
|
it.name,
|
||||||
it.url!!,
|
it.url,
|
||||||
it.mediaType ?: "application/octet-stream",
|
it.mediaType,
|
||||||
description = it.name
|
description = it.name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -144,10 +144,10 @@ class APNoteServiceImpl(
|
||||||
text = note.content,
|
text = note.content,
|
||||||
createdAt = Instant.parse(note.published).toEpochMilli(),
|
createdAt = Instant.parse(note.published).toEpochMilli(),
|
||||||
visibility = visibility,
|
visibility = visibility,
|
||||||
url = note.id ?: url,
|
url = note.id,
|
||||||
replyId = reply?.id,
|
replyId = reply?.id,
|
||||||
sensitive = note.sensitive,
|
sensitive = note.sensitive,
|
||||||
apId = note.id ?: url,
|
apId = note.id,
|
||||||
mediaIds = mediaList
|
mediaIds = mediaList
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -155,7 +155,7 @@ class APNoteServiceImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun fetchNote(note: Note, targetActor: String?): Note =
|
override suspend fun fetchNote(note: Note, targetActor: String?): Note =
|
||||||
saveIfMissing(note, targetActor, note.id ?: throw IllegalArgumentException("note.id is null"))
|
saveIfMissing(note, targetActor, note.id)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val public: String = "https://www.w3.org/ns/activitystreams#Public"
|
const val public: String = "https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
|
|
@ -83,7 +83,7 @@ class APUserServiceImpl(
|
||||||
} catch (ignore: FailedToGetResourcesException) {
|
} catch (ignore: FailedToGetResourcesException) {
|
||||||
val person = apResourceResolveService.resolve<Person>(url, null as Long?)
|
val person = apResourceResolveService.resolve<Person>(url, null as Long?)
|
||||||
|
|
||||||
val id = person.id ?: throw IllegalActivityPubObjectException("id is null")
|
val id = person.id
|
||||||
try {
|
try {
|
||||||
val userEntity = userQueryService.findByUrl(id)
|
val userEntity = userQueryService.findByUrl(id)
|
||||||
return entityToPerson(userEntity, id) to userEntity
|
return entityToPerson(userEntity, id) to userEntity
|
||||||
|
@ -94,11 +94,11 @@ class APUserServiceImpl(
|
||||||
name = person.preferredUsername
|
name = person.preferredUsername
|
||||||
?: throw IllegalActivityPubObjectException("preferredUsername is null"),
|
?: throw IllegalActivityPubObjectException("preferredUsername is null"),
|
||||||
domain = id.substringAfter("://").substringBefore("/"),
|
domain = id.substringAfter("://").substringBefore("/"),
|
||||||
screenName = (person.name ?: person.preferredUsername)
|
screenName = person.name
|
||||||
?: throw IllegalActivityPubObjectException("preferredUsername is null"),
|
?: throw IllegalActivityPubObjectException("preferredUsername is null"),
|
||||||
description = person.summary.orEmpty(),
|
description = person.summary.orEmpty(),
|
||||||
inbox = person.inbox ?: throw IllegalActivityPubObjectException("inbox is null"),
|
inbox = person.inbox,
|
||||||
outbox = person.outbox ?: throw IllegalActivityPubObjectException("outbox is null"),
|
outbox = person.outbox,
|
||||||
url = id,
|
url = id,
|
||||||
publicKey = person.publicKey?.publicKeyPem
|
publicKey = person.publicKey?.publicKeyPem
|
||||||
?: throw IllegalActivityPubObjectException("publicKey is null"),
|
?: throw IllegalActivityPubObjectException("publicKey is null"),
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package dev.usbharu.hideout.core.domain.exception.media
|
package dev.usbharu.hideout.core.domain.exception.media
|
||||||
|
|
||||||
|
import java.io.Serial
|
||||||
|
|
||||||
open class MediaConvertException : MediaException {
|
open class MediaConvertException : MediaException {
|
||||||
constructor() : super()
|
constructor() : super()
|
||||||
constructor(message: String?) : super(message)
|
constructor(message: String?) : super(message)
|
||||||
|
@ -11,4 +13,9 @@ open class MediaConvertException : MediaException {
|
||||||
enableSuppression,
|
enableSuppression,
|
||||||
writableStackTrace
|
writableStackTrace
|
||||||
)
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Serial
|
||||||
|
private const val serialVersionUID: Long = -6349105549968160551L
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package dev.usbharu.hideout.core.domain.exception.media
|
package dev.usbharu.hideout.core.domain.exception.media
|
||||||
|
|
||||||
|
import java.io.Serial
|
||||||
|
|
||||||
abstract class MediaException : RuntimeException {
|
abstract class MediaException : RuntimeException {
|
||||||
constructor() : super()
|
constructor() : super()
|
||||||
constructor(message: String?) : super(message)
|
constructor(message: String?) : super(message)
|
||||||
|
@ -11,4 +13,9 @@ abstract class MediaException : RuntimeException {
|
||||||
enableSuppression,
|
enableSuppression,
|
||||||
writableStackTrace
|
writableStackTrace
|
||||||
)
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Serial
|
||||||
|
private const val serialVersionUID: Long = 5988922562494187852L
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package dev.usbharu.hideout.core.domain.exception.media
|
package dev.usbharu.hideout.core.domain.exception.media
|
||||||
|
|
||||||
|
import java.io.Serial
|
||||||
|
|
||||||
open class MediaFileSizeException : MediaException {
|
open class MediaFileSizeException : MediaException {
|
||||||
constructor() : super()
|
constructor() : super()
|
||||||
constructor(message: String?) : super(message)
|
constructor(message: String?) : super(message)
|
||||||
|
@ -11,4 +13,9 @@ open class MediaFileSizeException : MediaException {
|
||||||
enableSuppression,
|
enableSuppression,
|
||||||
writableStackTrace
|
writableStackTrace
|
||||||
)
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Serial
|
||||||
|
private const val serialVersionUID: Long = 8672626879026555064L
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package dev.usbharu.hideout.core.domain.exception.media
|
package dev.usbharu.hideout.core.domain.exception.media
|
||||||
|
|
||||||
|
import java.io.Serial
|
||||||
|
|
||||||
class MediaFileSizeIsZeroException : MediaFileSizeException {
|
class MediaFileSizeIsZeroException : MediaFileSizeException {
|
||||||
constructor() : super()
|
constructor() : super()
|
||||||
constructor(message: String?) : super(message)
|
constructor(message: String?) : super(message)
|
||||||
|
@ -11,4 +13,9 @@ class MediaFileSizeIsZeroException : MediaFileSizeException {
|
||||||
enableSuppression,
|
enableSuppression,
|
||||||
writableStackTrace
|
writableStackTrace
|
||||||
)
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Serial
|
||||||
|
private const val serialVersionUID: Long = -2398394583775317875L
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package dev.usbharu.hideout.core.domain.exception.media
|
package dev.usbharu.hideout.core.domain.exception.media
|
||||||
|
|
||||||
|
import java.io.Serial
|
||||||
|
|
||||||
class MediaProcessException : MediaException {
|
class MediaProcessException : MediaException {
|
||||||
constructor() : super()
|
constructor() : super()
|
||||||
constructor(message: String?) : super(message)
|
constructor(message: String?) : super(message)
|
||||||
|
@ -11,4 +13,9 @@ class MediaProcessException : MediaException {
|
||||||
enableSuppression,
|
enableSuppression,
|
||||||
writableStackTrace
|
writableStackTrace
|
||||||
)
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Serial
|
||||||
|
private const val serialVersionUID: Long = -5195233013542703735L
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package dev.usbharu.hideout.core.domain.exception.media
|
package dev.usbharu.hideout.core.domain.exception.media
|
||||||
|
|
||||||
|
import java.io.Serial
|
||||||
|
|
||||||
class UnsupportedMediaException : MediaException {
|
class UnsupportedMediaException : MediaException {
|
||||||
constructor() : super()
|
constructor() : super()
|
||||||
constructor(message: String?) : super(message)
|
constructor(message: String?) : super(message)
|
||||||
|
@ -11,4 +13,9 @@ class UnsupportedMediaException : MediaException {
|
||||||
enableSuppression,
|
enableSuppression,
|
||||||
writableStackTrace
|
writableStackTrace
|
||||||
)
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Serial
|
||||||
|
private const val serialVersionUID: Long = -116741513216017134L
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
package dev.usbharu.hideout.core.domain.model.instance
|
package dev.usbharu.hideout.core.domain.model.instance
|
||||||
|
|
||||||
class Nodeinfo {
|
class Nodeinfo private constructor() {
|
||||||
|
|
||||||
var links: List<Links> = emptyList()
|
var links: List<Links> = emptyList()
|
||||||
|
|
||||||
private constructor()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Links {
|
class Links private constructor() {
|
||||||
var rel: String? = null
|
var rel: String? = null
|
||||||
var href: String? = null
|
var href: String? = null
|
||||||
|
|
||||||
private constructor()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,23 +3,17 @@
|
||||||
package dev.usbharu.hideout.core.domain.model.instance
|
package dev.usbharu.hideout.core.domain.model.instance
|
||||||
|
|
||||||
@Suppress("ClassNaming")
|
@Suppress("ClassNaming")
|
||||||
class Nodeinfo2_0 {
|
class Nodeinfo2_0() {
|
||||||
var metadata: Metadata? = null
|
var metadata: Metadata? = null
|
||||||
var software: Software? = null
|
var software: Software? = null
|
||||||
|
|
||||||
constructor()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Metadata {
|
class Metadata() {
|
||||||
var nodeName: String? = null
|
var nodeName: String? = null
|
||||||
var nodeDescription: String? = null
|
var nodeDescription: String? = null
|
||||||
|
|
||||||
constructor()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Software {
|
class Software() {
|
||||||
var name: String? = null
|
var name: String? = null
|
||||||
var version: String? = null
|
var version: String? = null
|
||||||
|
|
||||||
constructor()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ class InstanceRepositoryImpl(private val idGenerateService: IdGenerateService) :
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun delete(instance: InstanceEntity) {
|
override suspend fun delete(instance: InstanceEntity) {
|
||||||
Instance.deleteWhere { Instance.id eq instance.id }
|
Instance.deleteWhere { id eq instance.id }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ class ExposedOAuth2AuthorizationService(
|
||||||
it[accessTokenMetadata] = accessToken?.metadata?.let { it1 -> mapToJson(it1) }
|
it[accessTokenMetadata] = accessToken?.metadata?.let { it1 -> mapToJson(it1) }
|
||||||
it[accessTokenType] = accessToken?.token?.tokenType?.value
|
it[accessTokenType] = accessToken?.token?.tokenType?.value
|
||||||
it[accessTokenScopes] =
|
it[accessTokenScopes] =
|
||||||
accessToken?.run { token.scopes.joinToString(",").takeIf { it.isNotEmpty() } }
|
accessToken?.run { token.scopes.joinToString(",").takeIf { s -> s.isNotEmpty() } }
|
||||||
it[refreshTokenValue] = refreshToken?.token?.tokenValue
|
it[refreshTokenValue] = refreshToken?.token?.tokenValue
|
||||||
it[refreshTokenIssuedAt] = refreshToken?.token?.issuedAt
|
it[refreshTokenIssuedAt] = refreshToken?.token?.issuedAt
|
||||||
it[refreshTokenExpiresAt] = refreshToken?.token?.expiresAt
|
it[refreshTokenExpiresAt] = refreshToken?.token?.expiresAt
|
||||||
|
|
|
@ -53,7 +53,7 @@ class InstanceServiceImpl(
|
||||||
name = nodeinfo20.metadata?.nodeName,
|
name = nodeinfo20.metadata?.nodeName,
|
||||||
description = nodeinfo20.metadata?.nodeDescription,
|
description = nodeinfo20.metadata?.nodeDescription,
|
||||||
url = resolveInstanceUrl,
|
url = resolveInstanceUrl,
|
||||||
iconUrl = resolveInstanceUrl + "/favicon.ico",
|
iconUrl = "$resolveInstanceUrl/favicon.ico",
|
||||||
sharedInbox = sharedInbox,
|
sharedInbox = sharedInbox,
|
||||||
software = nodeinfo20.software?.name,
|
software = nodeinfo20.software?.name,
|
||||||
version = nodeinfo20.software?.version
|
version = nodeinfo20.software?.version
|
||||||
|
@ -72,7 +72,7 @@ class InstanceServiceImpl(
|
||||||
name = nodeinfo20.metadata?.nodeName,
|
name = nodeinfo20.metadata?.nodeName,
|
||||||
description = nodeinfo20.metadata?.nodeDescription,
|
description = nodeinfo20.metadata?.nodeDescription,
|
||||||
url = resolveInstanceUrl,
|
url = resolveInstanceUrl,
|
||||||
iconUrl = resolveInstanceUrl + "/favicon.ico",
|
iconUrl = "$resolveInstanceUrl/favicon.ico",
|
||||||
sharedInbox = sharedInbox,
|
sharedInbox = sharedInbox,
|
||||||
software = nodeinfo20.software?.name,
|
software = nodeinfo20.software?.name,
|
||||||
version = nodeinfo20.software?.version
|
version = nodeinfo20.software?.version
|
||||||
|
|
|
@ -5,4 +5,29 @@ data class MediaSave(
|
||||||
val prefix: String,
|
val prefix: String,
|
||||||
val fileInputStream: ByteArray,
|
val fileInputStream: ByteArray,
|
||||||
val thumbnailInputStream: ByteArray?
|
val thumbnailInputStream: ByteArray?
|
||||||
)
|
) {
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as MediaSave
|
||||||
|
|
||||||
|
if (name != other.name) return false
|
||||||
|
if (prefix != other.prefix) return false
|
||||||
|
if (!fileInputStream.contentEquals(other.fileInputStream)) return false
|
||||||
|
if (thumbnailInputStream != null) {
|
||||||
|
if (other.thumbnailInputStream == null) return false
|
||||||
|
if (!thumbnailInputStream.contentEquals(other.thumbnailInputStream)) return false
|
||||||
|
} else if (other.thumbnailInputStream != null) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = name.hashCode()
|
||||||
|
result = 31 * result + prefix.hashCode()
|
||||||
|
result = 31 * result + fileInputStream.contentHashCode()
|
||||||
|
result = 31 * result + (thumbnailInputStream?.contentHashCode() ?: 0)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ import dev.usbharu.hideout.core.domain.model.media.Media as EntityMedia
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Suppress("TooGenericExceptionCaught")
|
@Suppress("TooGenericExceptionCaught")
|
||||||
open class MediaServiceImpl(
|
class MediaServiceImpl(
|
||||||
private val mediaDataStore: MediaDataStore,
|
private val mediaDataStore: MediaDataStore,
|
||||||
private val fileTypeDeterminationService: FileTypeDeterminationService,
|
private val fileTypeDeterminationService: FileTypeDeterminationService,
|
||||||
private val mediaBlurhashService: MediaBlurhashService,
|
private val mediaBlurhashService: MediaBlurhashService,
|
||||||
|
|
|
@ -3,4 +3,22 @@ package dev.usbharu.hideout.core.service.media
|
||||||
data class ProcessedFile(
|
data class ProcessedFile(
|
||||||
val byteArray: ByteArray,
|
val byteArray: ByteArray,
|
||||||
val extension: String
|
val extension: String
|
||||||
)
|
) {
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as ProcessedFile
|
||||||
|
|
||||||
|
if (!byteArray.contentEquals(other.byteArray)) return false
|
||||||
|
if (extension != other.extension) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = byteArray.contentHashCode()
|
||||||
|
result = 31 * result + extension.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import dev.usbharu.hideout.core.domain.model.reaction.Reaction
|
||||||
import dev.usbharu.hideout.core.domain.model.reaction.ReactionRepository
|
import dev.usbharu.hideout.core.domain.model.reaction.ReactionRepository
|
||||||
import dev.usbharu.hideout.core.query.ReactionQueryService
|
import dev.usbharu.hideout.core.query.ReactionQueryService
|
||||||
import org.jetbrains.exposed.exceptions.ExposedSQLException
|
import org.jetbrains.exposed.exceptions.ExposedSQLException
|
||||||
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@ -50,6 +51,6 @@ class ReactionServiceImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val LOGGER = LoggerFactory.getLogger(ReactionServiceImpl::class.java)
|
val LOGGER: Logger = LoggerFactory.getLogger(ReactionServiceImpl::class.java)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ class InMemoryCacheManager : CacheManager {
|
||||||
keyMutex.withLock {
|
keyMutex.withLock {
|
||||||
cacheKey.filter { Instant.ofEpochMilli(it.value).plusSeconds(300) <= Instant.now() }
|
cacheKey.filter { Instant.ofEpochMilli(it.value).plusSeconds(300) <= Instant.now() }
|
||||||
|
|
||||||
val cached = cacheKey.get(key)
|
val cached = cacheKey[key]
|
||||||
if (cached == null) {
|
if (cached == null) {
|
||||||
needRunBlock = true
|
needRunBlock = true
|
||||||
cacheKey[key] = Instant.now().toEpochMilli()
|
cacheKey[key] = Instant.now().toEpochMilli()
|
||||||
|
|
|
@ -52,8 +52,7 @@ class UserServiceImpl(
|
||||||
createdAt = Instant.now(),
|
createdAt = Instant.now(),
|
||||||
following = "$userUrl/following",
|
following = "$userUrl/following",
|
||||||
followers = "$userUrl/followers",
|
followers = "$userUrl/followers",
|
||||||
keyId = "$userUrl#pubkey",
|
keyId = "$userUrl#pubkey"
|
||||||
instance = null
|
|
||||||
)
|
)
|
||||||
return userRepository.save(userEntity)
|
return userRepository.save(userEntity)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package dev.usbharu.hideout.generate
|
package dev.usbharu.hideout.generate
|
||||||
|
|
||||||
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.core.MethodParameter
|
import org.springframework.core.MethodParameter
|
||||||
import org.springframework.web.bind.support.WebDataBinderFactory
|
import org.springframework.web.bind.support.WebDataBinderFactory
|
||||||
|
@ -49,6 +50,6 @@ class JsonOrFormModelMethodProcessor(
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val logger = LoggerFactory.getLogger(JsonOrFormModelMethodProcessor::class.java)
|
val logger: Logger = LoggerFactory.getLogger(JsonOrFormModelMethodProcessor::class.java)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import org.jetbrains.exposed.sql.select
|
||||||
import org.springframework.stereotype.Repository
|
import org.springframework.stereotype.Repository
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
|
@Suppress("IncompleteDestructuring")
|
||||||
@Repository
|
@Repository
|
||||||
class StatusQueryServiceImpl : StatusQueryService {
|
class StatusQueryServiceImpl : StatusQueryService {
|
||||||
override suspend fun findByPostIds(ids: List<Long>): List<Status> = findByPostIdsWithMedia(ids)
|
override suspend fun findByPostIds(ids: List<Long>): List<Status> = findByPostIdsWithMedia(ids)
|
||||||
|
|
|
@ -25,7 +25,6 @@ class MediaApiServiceImpl(private val mediaService: MediaService, private val tr
|
||||||
type = type,
|
type = type,
|
||||||
url = uploadLocalMedia.url,
|
url = uploadLocalMedia.url,
|
||||||
previewUrl = uploadLocalMedia.thumbnailUrl,
|
previewUrl = uploadLocalMedia.thumbnailUrl,
|
||||||
remoteUrl = null,
|
|
||||||
description = mediaRequest.description,
|
description = mediaRequest.description,
|
||||||
blurhash = uploadLocalMedia.blurHash,
|
blurhash = uploadLocalMedia.blurHash,
|
||||||
textUrl = uploadLocalMedia.url
|
textUrl = uploadLocalMedia.url
|
||||||
|
|
|
@ -35,7 +35,7 @@ object AcctUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
throw IllegalArgumentException("Invalid acct.(Too many @)")
|
throw IllegalArgumentException("Invalid acct. (Too many @)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,10 @@ package dev.usbharu.hideout.util
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
|
|
||||||
object HttpUtil {
|
object HttpUtil {
|
||||||
val ContentType.Application.Activity: ContentType
|
val Activity: ContentType
|
||||||
get() = ContentType("application", "activity+json")
|
get() = ContentType("application", "activity+json")
|
||||||
|
|
||||||
val ContentType.Application.JsonLd: ContentType
|
val JsonLd: ContentType
|
||||||
get() {
|
get() {
|
||||||
return ContentType(
|
return ContentType(
|
||||||
contentType = "application",
|
contentType = "application",
|
||||||
|
|
Loading…
Reference in New Issue