mirror of https://github.com/usbharu/Hideout.git
Compare commits
11 Commits
2b4b33fe89
...
4bec7a49d6
Author | SHA1 | Date |
---|---|---|
usbharu | 4bec7a49d6 | |
usbharu | 5c62b929b5 | |
usbharu | a5c7de6535 | |
usbharu | 3f3a5dcceb | |
usbharu | b1d0747038 | |
usbharu | cd442d7f51 | |
usbharu | 7caae2cbaa | |
usbharu | a51cdee118 | |
usbharu | 0dd7facbad | |
usbharu | fdc6e1bae4 | |
usbharu | 673971e8f5 |
|
@ -37,3 +37,5 @@ out/
|
|||
*.db
|
||||
/src/main/resources/static/
|
||||
/node_modules/
|
||||
/src/main/web/generated/
|
||||
/stats.html
|
||||
|
|
|
@ -80,12 +80,14 @@ dependencies {
|
|||
implementation("org.xerial:sqlite-jdbc:3.40.1.0")
|
||||
implementation("io.ktor:ktor-server-websockets-jvm:$ktor_version")
|
||||
implementation("io.ktor:ktor-server-cio-jvm:$ktor_version")
|
||||
implementation("io.ktor:ktor-server-compression:$ktor_version")
|
||||
implementation("ch.qos.logback:logback-classic:$logback_version")
|
||||
|
||||
implementation("io.insert-koin:koin-core:$koin_version")
|
||||
implementation("io.insert-koin:koin-ktor:$koin_version")
|
||||
implementation("io.insert-koin:koin-logger-slf4j:$koin_version")
|
||||
implementation("io.insert-koin:koin-annotations:1.2.0")
|
||||
implementation("io.ktor:ktor-server-compression-jvm:2.3.0")
|
||||
ksp("io.insert-koin:koin-ksp-compiler:1.2.0")
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",
|
||||
"spaces": 2,
|
||||
"generator-cli": {
|
||||
"version": "6.6.0",
|
||||
"generators": {
|
||||
"v3.0": {
|
||||
"generatorName": "typescript-fetch",
|
||||
"output": "src/main/web/generated",
|
||||
"glob": "src/main/resources/openapi/api.yaml",
|
||||
"additionalProperties": {
|
||||
"modelPropertyNaming": "camelCase",
|
||||
"supportsES6": true,
|
||||
"withInterfaces": true,
|
||||
"typescriptThreePlus": true,
|
||||
"useSingleRequestParameter": false,
|
||||
"prependFormOrBodyParameters": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
"devDependencies": {
|
||||
"@suid/vite-plugin": "^0.1.3",
|
||||
"typescript": "^5.0.4",
|
||||
"vite": "^4.2.1",
|
||||
"vite": "4.2.3",
|
||||
"vite-plugin-solid": "^2.7.0"
|
||||
}
|
||||
},
|
||||
|
@ -1552,9 +1552,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.2.1.tgz",
|
||||
"integrity": "sha512-7MKhqdy0ISo4wnvwtqZkjke6XN4taqQ2TBaTccLIpOKv7Vp2h4Y+NpmWCnGDeSvvn45KxvWgGyb0MkHvY1vgbg==",
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.2.3.tgz",
|
||||
"integrity": "sha512-kLU+m2q0Y434Y1kCy3TchefAdtFso0ILi0dLyFV8Us3InXTU11H/B5ZTqCKIQHzSKNxVG/yEx813EA9f1imQ9A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.17.5",
|
||||
|
@ -2643,9 +2643,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"vite": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.2.1.tgz",
|
||||
"integrity": "sha512-7MKhqdy0ISo4wnvwtqZkjke6XN4taqQ2TBaTccLIpOKv7Vp2h4Y+NpmWCnGDeSvvn45KxvWgGyb0MkHvY1vgbg==",
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.2.3.tgz",
|
||||
"integrity": "sha512-kLU+m2q0Y434Y1kCy3TchefAdtFso0ILi0dLyFV8Us3InXTU11H/B5ZTqCKIQHzSKNxVG/yEx813EA9f1imQ9A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"esbuild": "^0.17.5",
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.0.4",
|
||||
"vite": "^4.2.1",
|
||||
"vite": "4.2.3",
|
||||
"vite-plugin-solid": "^2.7.0",
|
||||
"@suid/vite-plugin": "^0.1.3"
|
||||
},
|
||||
|
|
|
@ -95,17 +95,15 @@ fun Application.parent() {
|
|||
runBlocking {
|
||||
inject<IServerInitialiseService>().value.init()
|
||||
}
|
||||
configureCompression()
|
||||
configureHTTP()
|
||||
configureStaticRouting()
|
||||
configureMonitoring()
|
||||
configureSerialization()
|
||||
register(inject<IUserService>().value)
|
||||
configureSecurity(
|
||||
inject<IUserAuthService>().value,
|
||||
inject<IMetaService>().value,
|
||||
inject<IUserRepository>().value,
|
||||
inject<IJwtService>().value,
|
||||
inject<JwkProvider>().value,
|
||||
inject<IMetaService>().value
|
||||
)
|
||||
configureRouting(
|
||||
httpSignatureVerifyService = inject<HttpSignatureVerifyService>().value,
|
||||
|
@ -114,6 +112,10 @@ fun Application.parent() {
|
|||
activityPubUserService = inject<ActivityPubUserService>().value,
|
||||
postService = inject<IPostApiService>().value,
|
||||
userApiService = inject<IUserApiService>().value,
|
||||
userAuthService = inject<IUserAuthService>().value,
|
||||
userRepository = inject<IUserRepository>().value,
|
||||
jwtService = inject<IJwtService>().value,
|
||||
metaService = inject<IMetaService>().value
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@ open class Note : Object {
|
|||
var inReplyTo: String? = null
|
||||
|
||||
protected constructor() : super()
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
constructor(
|
||||
type: List<String> = emptyList(),
|
||||
name: String,
|
||||
|
|
|
@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.JsonNode
|
|||
import dev.usbharu.hideout.service.activitypub.ExtendedActivityVocabulary
|
||||
|
||||
class ObjectDeserializer : JsonDeserializer<Object>() {
|
||||
@Suppress("LongMethod")
|
||||
override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): Object {
|
||||
requireNotNull(p)
|
||||
val treeNode: JsonNode = requireNotNull(p.codec?.readTree(p))
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package dev.usbharu.hideout.domain.model.hideout.dto
|
||||
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.Visibility
|
||||
|
||||
data class PostResponse(
|
||||
val id: Long,
|
||||
val user: UserResponse,
|
||||
val overview: String? = null,
|
||||
val text: String? = null,
|
||||
val createdAt: Long,
|
||||
val visibility: Visibility,
|
||||
val url: String,
|
||||
val sensitive: Boolean = false,
|
||||
) {
|
||||
companion object {
|
||||
fun from(post: Post, user: User): PostResponse {
|
||||
return PostResponse(
|
||||
id = post.id,
|
||||
user = UserResponse.from(user),
|
||||
overview = post.overview,
|
||||
text = post.text,
|
||||
createdAt = post.createdAt,
|
||||
visibility = post.visibility,
|
||||
url = post.url,
|
||||
sensitive = post.sensitive
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package dev.usbharu.hideout.plugins
|
||||
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.plugins.compression.*
|
||||
|
||||
fun Application.configureCompression() {
|
||||
install(Compression) {
|
||||
gzip {
|
||||
matchContentType(ContentType.Application.JavaScript)
|
||||
priority = 1.0
|
||||
}
|
||||
deflate {
|
||||
matchContentType(ContentType.Application.JavaScript)
|
||||
priority = 10.0
|
||||
minimumSize(1024) // condition
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
package dev.usbharu.hideout.plugins
|
||||
|
||||
import dev.usbharu.hideout.repository.IUserRepository
|
||||
import dev.usbharu.hideout.routing.activitypub.inbox
|
||||
import dev.usbharu.hideout.routing.activitypub.outbox
|
||||
import dev.usbharu.hideout.routing.activitypub.usersAP
|
||||
import dev.usbharu.hideout.routing.api.internal.v1.auth
|
||||
import dev.usbharu.hideout.routing.api.internal.v1.posts
|
||||
import dev.usbharu.hideout.routing.api.internal.v1.users
|
||||
import dev.usbharu.hideout.routing.wellknown.webfinger
|
||||
|
@ -11,6 +13,9 @@ import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
|
|||
import dev.usbharu.hideout.service.api.IPostApiService
|
||||
import dev.usbharu.hideout.service.api.IUserApiService
|
||||
import dev.usbharu.hideout.service.auth.HttpSignatureVerifyService
|
||||
import dev.usbharu.hideout.service.auth.IJwtService
|
||||
import dev.usbharu.hideout.service.core.IMetaService
|
||||
import dev.usbharu.hideout.service.user.IUserAuthService
|
||||
import dev.usbharu.hideout.service.user.IUserService
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.plugins.autohead.*
|
||||
|
@ -23,7 +28,11 @@ fun Application.configureRouting(
|
|||
userService: IUserService,
|
||||
activityPubUserService: ActivityPubUserService,
|
||||
postService: IPostApiService,
|
||||
userApiService: IUserApiService
|
||||
userApiService: IUserApiService,
|
||||
userAuthService: IUserAuthService,
|
||||
userRepository: IUserRepository,
|
||||
jwtService: IJwtService,
|
||||
metaService: IMetaService
|
||||
) {
|
||||
install(AutoHeadResponse)
|
||||
routing {
|
||||
|
@ -34,6 +43,7 @@ fun Application.configureRouting(
|
|||
route("/api/internal/v1") {
|
||||
posts(postService)
|
||||
users(userService, userApiService)
|
||||
auth(userAuthService, userRepository, jwtService)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,19 +2,12 @@ package dev.usbharu.hideout.plugins
|
|||
|
||||
import com.auth0.jwk.JwkProvider
|
||||
import dev.usbharu.hideout.config.Config
|
||||
import dev.usbharu.hideout.domain.model.hideout.form.RefreshToken
|
||||
import dev.usbharu.hideout.domain.model.hideout.form.UserLogin
|
||||
import dev.usbharu.hideout.exception.UserNotFoundException
|
||||
import dev.usbharu.hideout.repository.IUserRepository
|
||||
import dev.usbharu.hideout.service.auth.IJwtService
|
||||
import dev.usbharu.hideout.service.core.IMetaService
|
||||
import dev.usbharu.hideout.service.user.IUserAuthService
|
||||
import dev.usbharu.hideout.util.JsonWebKeyUtil
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.auth.*
|
||||
import io.ktor.server.auth.jwt.*
|
||||
import io.ktor.server.request.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
|
||||
|
@ -22,11 +15,8 @@ const val TOKEN_AUTH = "jwt-auth"
|
|||
|
||||
@Suppress("MagicNumber")
|
||||
fun Application.configureSecurity(
|
||||
userAuthService: IUserAuthService,
|
||||
metaService: IMetaService,
|
||||
userRepository: IUserRepository,
|
||||
jwtService: IJwtService,
|
||||
jwkProvider: JwkProvider
|
||||
jwkProvider: JwkProvider,
|
||||
metaService: IMetaService
|
||||
) {
|
||||
val issuer = Config.configData.url
|
||||
install(Authentication) {
|
||||
|
@ -48,24 +38,6 @@ fun Application.configureSecurity(
|
|||
}
|
||||
|
||||
routing {
|
||||
post("/login") {
|
||||
val loginUser = call.receive<UserLogin>()
|
||||
val check = userAuthService.verifyAccount(loginUser.username, loginUser.password)
|
||||
if (check.not()) {
|
||||
return@post call.respond(HttpStatusCode.Unauthorized)
|
||||
}
|
||||
|
||||
val user = userRepository.findByNameAndDomain(loginUser.username, Config.configData.domain)
|
||||
?: throw UserNotFoundException("${loginUser.username} was not found.")
|
||||
|
||||
return@post call.respond(jwtService.createToken(user))
|
||||
}
|
||||
|
||||
post("/refresh-token") {
|
||||
val refreshToken = call.receive<RefreshToken>()
|
||||
return@post call.respond(jwtService.refreshToken(refreshToken))
|
||||
}
|
||||
|
||||
get("/.well-known/jwks.json") {
|
||||
//language=JSON
|
||||
val jwt = metaService.getJwtMeta()
|
||||
|
@ -74,12 +46,5 @@ fun Application.configureSecurity(
|
|||
text = JsonWebKeyUtil.publicKeyToJwk(jwt.publicKey, jwt.kid.toString())
|
||||
)
|
||||
}
|
||||
authenticate(TOKEN_AUTH) {
|
||||
get("/auth-check") {
|
||||
val principal = call.principal<JWTPrincipal>() ?: throw IllegalStateException("no principal")
|
||||
val username = principal.payload.getClaim("uid")
|
||||
call.respondText("Hello $username")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,7 +88,9 @@ class PostRepositoryImpl(database: Database, private val idGenerateService: IdGe
|
|||
limit: Int?,
|
||||
userId: Long?
|
||||
): List<Post> {
|
||||
TODO("Not yet implemented")
|
||||
return query {
|
||||
Posts.select { Posts.visibility eq Visibility.PUBLIC.ordinal }.map { it.toPost() }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun findByUserNameAndDomain(
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package dev.usbharu.hideout.routing.api.internal.v1
|
||||
|
||||
import dev.usbharu.hideout.config.Config
|
||||
import dev.usbharu.hideout.domain.model.hideout.form.RefreshToken
|
||||
import dev.usbharu.hideout.domain.model.hideout.form.UserLogin
|
||||
import dev.usbharu.hideout.exception.UserNotFoundException
|
||||
import dev.usbharu.hideout.plugins.TOKEN_AUTH
|
||||
import dev.usbharu.hideout.repository.IUserRepository
|
||||
import dev.usbharu.hideout.service.auth.IJwtService
|
||||
import dev.usbharu.hideout.service.user.IUserAuthService
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.auth.*
|
||||
import io.ktor.server.auth.jwt.*
|
||||
import io.ktor.server.request.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
|
||||
fun Route.auth(
|
||||
userAuthService: IUserAuthService,
|
||||
userRepository: IUserRepository,
|
||||
jwtService: IJwtService
|
||||
) {
|
||||
post("/login") {
|
||||
val loginUser = call.receive<UserLogin>()
|
||||
val check = userAuthService.verifyAccount(loginUser.username, loginUser.password)
|
||||
if (check.not()) {
|
||||
return@post call.respond(HttpStatusCode.Unauthorized)
|
||||
}
|
||||
|
||||
val user = userRepository.findByNameAndDomain(loginUser.username, Config.configData.domain)
|
||||
?: throw UserNotFoundException("${loginUser.username} was not found.")
|
||||
|
||||
return@post call.respond(jwtService.createToken(user))
|
||||
}
|
||||
|
||||
post("/refresh-token") {
|
||||
val refreshToken = call.receive<RefreshToken>()
|
||||
return@post call.respond(jwtService.refreshToken(refreshToken))
|
||||
}
|
||||
authenticate(TOKEN_AUTH) {
|
||||
get("/auth-check") {
|
||||
val principal = call.principal<JWTPrincipal>() ?: throw IllegalStateException("no principal")
|
||||
val username = principal.payload.getClaim("uid")
|
||||
call.respondText("Hello $username")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
package dev.usbharu.hideout.service.api
|
||||
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||
import dev.usbharu.hideout.domain.model.hideout.dto.PostResponse
|
||||
import java.time.Instant
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
interface IPostApiService {
|
||||
suspend fun createPost(postForm: dev.usbharu.hideout.domain.model.hideout.form.Post, userId: Long): Post
|
||||
suspend fun getById(id: Long, userId: Long?): Post
|
||||
suspend fun createPost(postForm: dev.usbharu.hideout.domain.model.hideout.form.Post, userId: Long): PostResponse
|
||||
suspend fun getById(id: Long, userId: Long?): PostResponse
|
||||
suspend fun getAll(
|
||||
since: Instant? = null,
|
||||
until: Instant? = null,
|
||||
|
@ -14,7 +14,7 @@ interface IPostApiService {
|
|||
maxId: Long? = null,
|
||||
limit: Int? = null,
|
||||
userId: Long? = null
|
||||
): List<Post>
|
||||
): List<PostResponse>
|
||||
|
||||
suspend fun getByUser(
|
||||
nameOrId: String,
|
||||
|
@ -24,5 +24,5 @@ interface IPostApiService {
|
|||
maxId: Long? = null,
|
||||
limit: Int? = null,
|
||||
userId: Long? = null
|
||||
): List<Post>
|
||||
): List<PostResponse>
|
||||
}
|
||||
|
|
|
@ -2,11 +2,16 @@ package dev.usbharu.hideout.service.api
|
|||
|
||||
import dev.usbharu.hideout.config.Config
|
||||
import dev.usbharu.hideout.domain.model.hideout.dto.PostCreateDto
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||
import dev.usbharu.hideout.exception.PostNotFoundException
|
||||
import dev.usbharu.hideout.repository.IPostRepository
|
||||
import dev.usbharu.hideout.domain.model.hideout.dto.PostResponse
|
||||
import dev.usbharu.hideout.repository.*
|
||||
import dev.usbharu.hideout.service.post.IPostService
|
||||
import dev.usbharu.hideout.util.AcctUtil
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import org.jetbrains.exposed.sql.and
|
||||
import org.jetbrains.exposed.sql.innerJoin
|
||||
import org.jetbrains.exposed.sql.select
|
||||
import org.jetbrains.exposed.sql.selectAll
|
||||
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
|
||||
import org.koin.core.annotation.Single
|
||||
import java.time.Instant
|
||||
import dev.usbharu.hideout.domain.model.hideout.form.Post as FormPost
|
||||
|
@ -14,10 +19,11 @@ import dev.usbharu.hideout.domain.model.hideout.form.Post as FormPost
|
|||
@Single
|
||||
class PostApiServiceImpl(
|
||||
private val postService: IPostService,
|
||||
private val postRepository: IPostRepository
|
||||
private val postRepository: IPostRepository,
|
||||
private val userRepository: IUserRepository
|
||||
) : IPostApiService {
|
||||
override suspend fun createPost(postForm: FormPost, userId: Long): Post {
|
||||
return postService.createLocal(
|
||||
override suspend fun createPost(postForm: FormPost, userId: Long): PostResponse {
|
||||
val createdPost = postService.createLocal(
|
||||
PostCreateDto(
|
||||
text = postForm.text,
|
||||
overview = postForm.overview,
|
||||
|
@ -27,11 +33,20 @@ class PostApiServiceImpl(
|
|||
userId = userId
|
||||
)
|
||||
)
|
||||
val creator = userRepository.findById(userId)
|
||||
return PostResponse.from(createdPost, creator!!)
|
||||
}
|
||||
|
||||
override suspend fun getById(id: Long, userId: Long?): Post {
|
||||
return postRepository.findOneById(id, userId)
|
||||
?: throw PostNotFoundException("$id was not found or is not authorized.")
|
||||
@Suppress("InjectDispatcher")
|
||||
suspend fun <T> query(block: suspend () -> T): T =
|
||||
newSuspendedTransaction(Dispatchers.IO) { block() }
|
||||
|
||||
override suspend fun getById(id: Long, userId: Long?): PostResponse {
|
||||
val query = query {
|
||||
Posts.innerJoin(Users, onColumn = { Posts.userId }, otherColumn = { Users.id }).select { Posts.id eq id }
|
||||
.single()
|
||||
}
|
||||
return PostResponse.from(query.toPost(), query.toUser())
|
||||
}
|
||||
|
||||
override suspend fun getAll(
|
||||
|
@ -41,7 +56,12 @@ class PostApiServiceImpl(
|
|||
maxId: Long?,
|
||||
limit: Int?,
|
||||
userId: Long?
|
||||
): List<Post> = postRepository.findAll(since, until, minId, maxId, limit, userId)
|
||||
): List<PostResponse> {
|
||||
return query {
|
||||
Posts.innerJoin(Users, onColumn = { Posts.userId }, otherColumn = { id }).selectAll()
|
||||
.map { PostResponse.from(it.toPost(), it.toUser()) }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getByUser(
|
||||
nameOrId: String,
|
||||
|
@ -51,23 +71,22 @@ class PostApiServiceImpl(
|
|||
maxId: Long?,
|
||||
limit: Int?,
|
||||
userId: Long?
|
||||
): List<Post> {
|
||||
): List<PostResponse> {
|
||||
val idOrNull = nameOrId.toLongOrNull()
|
||||
return if (idOrNull == null) {
|
||||
val acct = AcctUtil.parse(nameOrId)
|
||||
postRepository.findByUserNameAndDomain(
|
||||
username = acct.username,
|
||||
s = acct.domain
|
||||
?: Config.configData.domain,
|
||||
since = since,
|
||||
until = until,
|
||||
minId = minId,
|
||||
maxId = maxId,
|
||||
limit = limit,
|
||||
userId = userId
|
||||
)
|
||||
query {
|
||||
Posts.innerJoin(Users, onColumn = { Posts.userId }, otherColumn = { id }).select {
|
||||
Users.name.eq(acct.username)
|
||||
.and(Users.domain eq (acct.domain ?: Config.configData.domain))
|
||||
}.map { PostResponse.from(it.toPost(), it.toUser()) }
|
||||
}
|
||||
} else {
|
||||
postRepository.findByUserId(idOrNull, since, until, minId, maxId, limit, userId)
|
||||
query {
|
||||
Posts.innerJoin(Users, onColumn = { Posts.userId }, otherColumn = { id }).select {
|
||||
Posts.userId eq idOrNull
|
||||
}.map { PostResponse.from(it.toPost(), it.toUser()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ class ExposedJobRepository(
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("SuspendFunWithFlowReturnType")
|
||||
override suspend fun findNext(names: Set<String>, status: Set<JobStatus>, limit: Int): Flow<ScheduledJob> {
|
||||
return query {
|
||||
jobs.select(
|
||||
|
|
|
@ -20,7 +20,7 @@ paths:
|
|||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Post"
|
||||
$ref: "#/components/schemas/PostResponse"
|
||||
401:
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
403:
|
||||
|
@ -37,7 +37,7 @@ paths:
|
|||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Post"
|
||||
$ref: "#/components/schemas/PostRequest"
|
||||
responses:
|
||||
200:
|
||||
description: 成功
|
||||
|
@ -65,7 +65,7 @@ paths:
|
|||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Post"
|
||||
$ref: "#/components/schemas/PostResponse"
|
||||
401:
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
403:
|
||||
|
@ -90,7 +90,7 @@ paths:
|
|||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Post"
|
||||
$ref: "#/components/schemas/PostResponse"
|
||||
401:
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
403:
|
||||
|
@ -114,7 +114,7 @@ paths:
|
|||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Post"
|
||||
$ref: "#/components/schemas/PostResponse"
|
||||
401:
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
403:
|
||||
|
@ -137,7 +137,7 @@ paths:
|
|||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/User"
|
||||
$ref: "#/components/schemas/UserResponse"
|
||||
|
||||
post:
|
||||
summary: ユーザーを作成する
|
||||
|
@ -181,7 +181,7 @@ paths:
|
|||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/User"
|
||||
$ref: "#/components/schemas/UserResponse"
|
||||
404:
|
||||
$ref: "#/components/responses/NotFound"
|
||||
|
||||
|
@ -198,7 +198,7 @@ paths:
|
|||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/User"
|
||||
$ref: "#/components/schemas/UserResponse"
|
||||
post:
|
||||
summary: ユーザーをフォローする
|
||||
security:
|
||||
|
@ -228,7 +228,47 @@ paths:
|
|||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/User"
|
||||
$ref: "#/components/schemas/UserResponse"
|
||||
|
||||
/login:
|
||||
post:
|
||||
summary: ログインする
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/UserLogin"
|
||||
responses:
|
||||
200:
|
||||
description: ログイン成功
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/JwtToken"
|
||||
|
||||
/refresh-token:
|
||||
post:
|
||||
summary: 期限切れトークンの再発行をする
|
||||
responses:
|
||||
200:
|
||||
description: トークンの再発行に成功
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/JwtToken"
|
||||
|
||||
/auth-check:
|
||||
get:
|
||||
summary: 認証チェック
|
||||
responses:
|
||||
200:
|
||||
description: 認証に成功
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
|
||||
components:
|
||||
responses:
|
||||
|
@ -261,8 +301,23 @@ components:
|
|||
type: string
|
||||
|
||||
schemas:
|
||||
User:
|
||||
Visibility:
|
||||
type: string
|
||||
enum:
|
||||
- public
|
||||
- unlisted
|
||||
- followers
|
||||
- direct
|
||||
UserResponse:
|
||||
type: object
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
- domain
|
||||
- screenName
|
||||
- description
|
||||
- url
|
||||
- createdAt
|
||||
properties:
|
||||
id:
|
||||
type: number
|
||||
|
@ -277,23 +332,30 @@ components:
|
|||
type: string
|
||||
description:
|
||||
type: string
|
||||
nullable: true
|
||||
url:
|
||||
type: string
|
||||
readOnly: true
|
||||
createdAt:
|
||||
type: number
|
||||
readOnly: true
|
||||
Post:
|
||||
PostResponse:
|
||||
type: object
|
||||
required:
|
||||
- id
|
||||
- user
|
||||
- text
|
||||
- createdAt
|
||||
- visibility
|
||||
- url
|
||||
- sensitive
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
readOnly: true
|
||||
userId:
|
||||
type: integer
|
||||
format: int64
|
||||
readOnly: true
|
||||
user:
|
||||
$ref: "#/components/schemas/UserResponse"
|
||||
overview:
|
||||
type: string
|
||||
text:
|
||||
|
@ -303,12 +365,7 @@ components:
|
|||
format: int64
|
||||
readOnly: true
|
||||
visibility:
|
||||
type: string
|
||||
enum:
|
||||
- public
|
||||
- unlisted
|
||||
- followers
|
||||
- direct
|
||||
$ref: "#/components/schemas/Visibility"
|
||||
url:
|
||||
type: string
|
||||
format: uri
|
||||
|
@ -323,13 +380,49 @@ components:
|
|||
readOnly: true
|
||||
sensitive:
|
||||
type: boolean
|
||||
apId:
|
||||
type: string
|
||||
format: url
|
||||
readOnly: true
|
||||
|
||||
PostRequest:
|
||||
type: object
|
||||
properties:
|
||||
overview:
|
||||
type: string
|
||||
text:
|
||||
type: string
|
||||
visibility:
|
||||
$ref: "#/components/schemas/Visibility"
|
||||
repostId:
|
||||
type: integer
|
||||
format: int64
|
||||
replyId:
|
||||
type: integer
|
||||
format: int64
|
||||
sensitive:
|
||||
type: boolean
|
||||
|
||||
JwtToken:
|
||||
type: object
|
||||
properties:
|
||||
token:
|
||||
type: string
|
||||
refreshToken:
|
||||
type: string
|
||||
|
||||
RefreshToken:
|
||||
type: object
|
||||
properties:
|
||||
refreshToken:
|
||||
type: string
|
||||
|
||||
UserLogin:
|
||||
type: object
|
||||
properties:
|
||||
username:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
|
||||
securitySchemes:
|
||||
BearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
|
|
|
@ -1,58 +1,44 @@
|
|||
import {Component, createSignal} from "solid-js";
|
||||
import {Component, createEffect, createSignal} from "solid-js";
|
||||
import {Route, Router, Routes} from "@solidjs/router";
|
||||
import {TopPage} from "./pages/TopPage";
|
||||
import {createTheme, CssBaseline, ThemeProvider, useMediaQuery} from "@suid/material";
|
||||
import {createCookieStorage} from "@solid-primitives/storage";
|
||||
import {ApiProvider} from "./lib/ApiProvider";
|
||||
import {Configuration, DefaultApi} from "./generated";
|
||||
import {LoginPage} from "./pages/LoginPage";
|
||||
|
||||
export const App: Component = () => {
|
||||
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
|
||||
const [cookie, setCookie] = createCookieStorage()
|
||||
const [api, setApi] = createSignal(new DefaultApi(new Configuration({
|
||||
basePath: window.location.origin + "/api/internal/v1",
|
||||
accessToken: cookie.token as string
|
||||
})))
|
||||
|
||||
const fn = (form: HTMLButtonElement) => {
|
||||
console.log(form)
|
||||
}
|
||||
|
||||
const [username, setUsername] = createSignal("")
|
||||
const [password, setPassword] = createSignal("")
|
||||
|
||||
return (
|
||||
<form onSubmit={function (e: SubmitEvent) {
|
||||
e.preventDefault()
|
||||
fetch("/login", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({username: username(), password: password()}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}).then(res => res.json())
|
||||
// .then(res => fetch("/auth-check", {
|
||||
// method: "GET",
|
||||
// headers: {
|
||||
// 'Authorization': 'Bearer ' + res.token
|
||||
// }
|
||||
// }))
|
||||
// .then(res => res.json())
|
||||
.then(res => {
|
||||
console.log(res.token);
|
||||
fetch("/refresh-token", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({refreshToken: res.refreshToken}),
|
||||
}).then(res=> res.json()).then(res => console.log(res.token))
|
||||
createEffect(() => {
|
||||
setApi(
|
||||
new DefaultApi(new Configuration({
|
||||
basePath: window.location.origin + "/api/internal/v1",
|
||||
accessToken : cookie.token as string
|
||||
})))
|
||||
})
|
||||
}
|
||||
|
||||
}>
|
||||
<input name="username" type="text" placeholder="Username" required
|
||||
onChange={(e) => setUsername(e.currentTarget.value)}/>
|
||||
<input name="password" type="password" placeholder="Password" required
|
||||
onChange={(e) => setPassword(e.currentTarget.value)}/>
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
const theme = createTheme({
|
||||
palette: {
|
||||
mode: prefersDarkMode() ? 'dark' : 'light',
|
||||
}
|
||||
})
|
||||
return (
|
||||
<ApiProvider api={api()}>
|
||||
<ThemeProvider theme={theme}>
|
||||
<CssBaseline/>
|
||||
<Router>
|
||||
<Routes>
|
||||
<Route path="/" component={TopPage}/>
|
||||
<Route path="/login" component={LoginPage}/>
|
||||
</Routes>
|
||||
</Router>
|
||||
</ThemeProvider>
|
||||
</ApiProvider>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
declare module 'solid-js' {
|
||||
namespace JSX {
|
||||
interface Directives {
|
||||
fn: (form: HTMLFormElement) => void
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
import {Avatar as SuidAvatar} from "@suid/material";
|
||||
import {Component, JSXElement} from "solid-js";
|
||||
|
||||
export const Avatar: Component<{ src: string }> = (props): JSXElement => {
|
||||
return (
|
||||
<SuidAvatar src={props.src}/>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import {ParentComponent} from "solid-js";
|
||||
import {Button, ListItem, ListItemAvatar, ListItemButton, ListItemIcon, ListItemText} from "@suid/material";
|
||||
import {Link} from "@solidjs/router";
|
||||
|
||||
export const SidebarButton: ParentComponent<{ text: string,linkTo:string }> = (props) => {
|
||||
return (
|
||||
<ListItem>
|
||||
<ListItemButton component={Link} href={props.linkTo}>
|
||||
<ListItemIcon>{props.children}</ListItemIcon>
|
||||
<ListItemText primary={props.text}/>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
import {createContextProvider} from "@solid-primitives/context";
|
||||
import {createSignal} from "solid-js";
|
||||
import {DefaultApi, DefaultApiInterface} from "../generated";
|
||||
|
||||
export const [ApiProvider,useApi] = createContextProvider((props:{api:DefaultApiInterface}) => {
|
||||
const [api,setApi] = createSignal(props.api);
|
||||
return api
|
||||
},()=>new DefaultApi());
|
|
@ -0,0 +1,16 @@
|
|||
import {DefaultApiInterface} from "../generated";
|
||||
|
||||
export class ApiWrapper {
|
||||
api: DefaultApiInterface;
|
||||
|
||||
constructor(initApi: DefaultApiInterface) {
|
||||
this.api = initApi;
|
||||
console.log(this.api);
|
||||
console.log(this.postsGet());
|
||||
}
|
||||
|
||||
postsGet = async () => this.api.postsGet()
|
||||
|
||||
usersUserNameGet = async (userName: string) => this.api.usersUserNameGet(userName);
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
import {Component, Match, Switch} from "solid-js";
|
||||
import {Home, Lock, Mail, Public} from "@suid/icons-material";
|
||||
import {IconButton} from "@suid/material";
|
||||
import {Visibility} from "../generated";
|
||||
|
||||
export const ShareScopeIndicator: Component<{ visibility: Visibility }> = (props) => {
|
||||
return <Switch fallback={<Public/>}>
|
||||
<Match when={props.visibility == "public"}>
|
||||
<IconButton>
|
||||
<Public/>
|
||||
</IconButton>
|
||||
</Match>
|
||||
<Match when={props.visibility == "direct"}>
|
||||
<IconButton>
|
||||
<Mail/>
|
||||
</IconButton>
|
||||
</Match>
|
||||
<Match when={props.visibility == "followers"}>
|
||||
<IconButton>
|
||||
<Lock/>
|
||||
</IconButton>
|
||||
</Match>
|
||||
<Match when={props.visibility == "unlisted"}>
|
||||
<IconButton>
|
||||
<Home/>
|
||||
</IconButton>
|
||||
</Match>
|
||||
</Switch>
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
import {Component, createSignal} from "solid-js";
|
||||
import {Box, Card, CardActions, CardContent, CardHeader, IconButton, Menu, MenuItem, Typography} from "@suid/material";
|
||||
import {Avatar} from "../atoms/Avatar";
|
||||
import {Favorite, MoreVert, Reply, ScreenRotationAlt} from "@suid/icons-material";
|
||||
import {ShareScopeIndicator} from "../molecules/ShareScopeIndicator";
|
||||
import {PostResponse} from "../generated";
|
||||
|
||||
export const Post: Component<{ post: PostResponse }> = (props) => {
|
||||
const [anchorEl, setAnchorEl] = createSignal<null | HTMLElement>(null)
|
||||
const open = () => Boolean(anchorEl());
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
}
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader avatar={<Avatar src={props.post.user.url + "/icon.jpg"}/>} title={props.post.user.screenName}
|
||||
subheader={`${props.post.user.name}@${props.post.user.domain}`}
|
||||
action={<IconButton onclick={(event) => {
|
||||
setAnchorEl(event.currentTarget)
|
||||
}}><MoreVert/><Menu disableScrollLock anchorEl={anchorEl()} open={open()} onClose={handleClose}><MenuItem
|
||||
onclick={handleClose}>aaa</MenuItem></Menu> </IconButton>}/>
|
||||
<CardContent>
|
||||
<Typography>
|
||||
{props.post.text}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
<CardActions disableSpacing>
|
||||
<IconButton>
|
||||
<Reply/>
|
||||
</IconButton>
|
||||
<IconButton>
|
||||
<ScreenRotationAlt/>
|
||||
</IconButton>
|
||||
<IconButton>
|
||||
<Favorite/>
|
||||
</IconButton>
|
||||
<Box sx={{marginLeft: "auto"}}>
|
||||
<Typography>{new Date(props.post.createdAt).toDateString()}</Typography>
|
||||
</Box>
|
||||
<ShareScopeIndicator visibility={props.post.visibility}/>
|
||||
</CardActions>
|
||||
</Card>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
import {Component, createSignal} from "solid-js";
|
||||
import {Button, IconButton, Paper, Stack, TextField, Typography} from "@suid/material";
|
||||
import {Avatar} from "../atoms/Avatar";
|
||||
import {AddPhotoAlternate, Poll, Public} from "@suid/icons-material";
|
||||
import {useApi} from "../lib/ApiProvider";
|
||||
|
||||
export const PostForm: Component<{ label: string }> = (props) => {
|
||||
const [text, setText] = createSignal("")
|
||||
const api = useApi()
|
||||
return (
|
||||
<Paper sx={{width: "100%"}}>
|
||||
<Stack>
|
||||
<Stack direction={"row"} spacing={2} sx={{padding: 2}}>
|
||||
<Avatar src={""}/>
|
||||
<TextField label={props.label} multiline rows={4} variant={"standard"} onChange={(event)=>setText(event.target.value)} fullWidth/>
|
||||
</Stack>
|
||||
<Stack direction={"row"} justifyContent={"space-between"} sx={{padding: 2}}>
|
||||
<Stack direction={"row"} justifyContent={"flex-start"} alignItems={"center"}>
|
||||
<IconButton>
|
||||
<AddPhotoAlternate/>
|
||||
</IconButton>
|
||||
<IconButton>
|
||||
<Poll/>
|
||||
</IconButton>
|
||||
<IconButton>
|
||||
<Public/>
|
||||
</IconButton>
|
||||
</Stack>
|
||||
<Stack direction={"row"} alignItems={"center"} spacing={2}>
|
||||
<Typography>
|
||||
aaa
|
||||
</Typography>
|
||||
<Button variant={"contained"} onClick={() => {
|
||||
api().postsPost({text: text()}).then(()=>setText(""))
|
||||
}}>
|
||||
投稿する
|
||||
</Button>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Paper>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
import {Button, Card, CardContent, CardHeader, Modal, Stack, TextField} from "@suid/material";
|
||||
import {Component, createSignal} from "solid-js";
|
||||
import {createCookieStorage} from "@solid-primitives/storage";
|
||||
import {useApi} from "../lib/ApiProvider";
|
||||
import {useNavigate} from "@solidjs/router";
|
||||
|
||||
export const LoginPage: Component = () => {
|
||||
const [username, setUsername] = createSignal("")
|
||||
const [password, setPassword] = createSignal("")
|
||||
|
||||
const [cookie, setCookie] = createCookieStorage();
|
||||
|
||||
const navigator = useNavigate();
|
||||
|
||||
const api = useApi();
|
||||
|
||||
const onSubmit: () => void = () => {
|
||||
api().loginPost({password: password(), username: username()}).then(value => {
|
||||
setCookie("token", value.token);
|
||||
setCookie("refresh-token", value.refreshToken)
|
||||
navigator("/")
|
||||
}).catch(reason => {
|
||||
console.log(reason);
|
||||
setPassword("")
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open>
|
||||
<Card>
|
||||
<CardHeader/>
|
||||
<CardContent>
|
||||
|
||||
<Stack spacing={3}>
|
||||
|
||||
<TextField
|
||||
value={username()}
|
||||
onChange={(event) => setUsername(event.target.value)}
|
||||
label="Username"
|
||||
type="text"
|
||||
autoComplete="username"
|
||||
variant="standard"
|
||||
/>
|
||||
<TextField
|
||||
value={password()}
|
||||
onChange={(event) => setPassword(event.target.value)}
|
||||
label="Password"
|
||||
type="password"
|
||||
autoComplete="current-password"
|
||||
variant="standard"
|
||||
/>
|
||||
<Button type={"submit"} onClick={onSubmit}>Login</Button>
|
||||
</Stack>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Modal>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
import {Component} from "solid-js";
|
||||
import {MainPage} from "../templates/MainPage";
|
||||
import {PostForm} from "../organisms/PostForm";
|
||||
import {Stack} from "@suid/material";
|
||||
import {PostResponse} from "../generated";
|
||||
import {PostList} from "../templates/PostList";
|
||||
import {useApi} from "../lib/ApiProvider";
|
||||
import {createStore} from "solid-js/store";
|
||||
|
||||
|
||||
export const TopPage: Component = () => {
|
||||
const api = useApi()
|
||||
const [posts, setPosts] = createStore<PostResponse[]>([])
|
||||
api().postsGet().then((res)=>setPosts(res))
|
||||
|
||||
return (
|
||||
<MainPage>
|
||||
<Stack spacing={1} alignItems={"stretch"}>
|
||||
<PostForm label={"投稿する"}/>
|
||||
<PostList posts={posts}/>
|
||||
</Stack>
|
||||
</MainPage>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import {createSignal, ParentComponent} from "solid-js";
|
||||
import {Grid} from "@suid/material";
|
||||
import {Sidebar} from "./Sidebar";
|
||||
|
||||
export const MainPage: ParentComponent = (props) => {
|
||||
return (
|
||||
<Grid container spacing={2} wrap={"nowrap"}>
|
||||
<Grid item xs={0} md={3}>
|
||||
<Sidebar/>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
{props.children}
|
||||
</Grid>
|
||||
<Grid item xs={0} md={3}>
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
)
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import {Component, For} from "solid-js";
|
||||
import {CircularProgress} from "@suid/material";
|
||||
import {Post} from "../organisms/Post";
|
||||
import {PostResponse} from "../generated";
|
||||
|
||||
export const PostList: Component<{ posts: PostResponse[] | undefined }> = (props) => {
|
||||
return (
|
||||
<For each={props.posts} fallback={<CircularProgress/>}>
|
||||
{
|
||||
(item, index) => <Post post={item}/>
|
||||
}
|
||||
</For>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import {Component} from "solid-js";
|
||||
import {Button, List, Stack} from "@suid/material";
|
||||
import {Home} from "@suid/icons-material";
|
||||
import {SidebarButton} from "../atoms/SidebarButton";
|
||||
|
||||
export const Sidebar: Component = (props) => {
|
||||
return (
|
||||
<List>
|
||||
<SidebarButton text={"AP"} linkTo={"/"}></SidebarButton>
|
||||
<SidebarButton text={"Home"} linkTo={"/"}><Home/></SidebarButton>
|
||||
</List>
|
||||
)
|
||||
}
|
|
@ -15,6 +15,7 @@ import dev.usbharu.hideout.domain.model.hideout.form.RefreshToken
|
|||
import dev.usbharu.hideout.domain.model.hideout.form.UserLogin
|
||||
import dev.usbharu.hideout.exception.InvalidRefreshTokenException
|
||||
import dev.usbharu.hideout.repository.IUserRepository
|
||||
import dev.usbharu.hideout.routing.api.internal.v1.auth
|
||||
import dev.usbharu.hideout.service.auth.IJwtService
|
||||
import dev.usbharu.hideout.service.core.IMetaService
|
||||
import dev.usbharu.hideout.service.user.IUserAuthService
|
||||
|
@ -24,6 +25,7 @@ import io.ktor.client.request.*
|
|||
import io.ktor.client.statement.*
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.config.*
|
||||
import io.ktor.server.routing.*
|
||||
import io.ktor.server.testing.*
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.ArgumentMatchers.anyString
|
||||
|
@ -70,7 +72,10 @@ class SecurityKtTest {
|
|||
val jwkProvider = mock<JwkProvider>()
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(userAuthService, metaService, userRepository, jwtService, jwkProvider)
|
||||
configureSecurity(jwkProvider, metaService)
|
||||
routing {
|
||||
auth(userAuthService, userRepository, jwtService)
|
||||
}
|
||||
}
|
||||
|
||||
client.post("/login") {
|
||||
|
@ -97,7 +102,10 @@ class SecurityKtTest {
|
|||
val jwkProvider = mock<JwkProvider>()
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(userAuthService, metaService, userRepository, jwtService, jwkProvider)
|
||||
configureSecurity(jwkProvider, metaService)
|
||||
routing {
|
||||
auth(userAuthService, userRepository, jwtService)
|
||||
}
|
||||
}
|
||||
client.post("/login") {
|
||||
contentType(ContentType.Application.Json)
|
||||
|
@ -122,7 +130,10 @@ class SecurityKtTest {
|
|||
val jwkProvider = mock<JwkProvider>()
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(userAuthService, metaService, userRepository, jwtService, jwkProvider)
|
||||
configureSecurity(jwkProvider, metaService)
|
||||
routing {
|
||||
auth(userAuthService, userRepository, jwtService)
|
||||
}
|
||||
}
|
||||
client.post("/login") {
|
||||
contentType(ContentType.Application.Json)
|
||||
|
@ -140,7 +151,10 @@ class SecurityKtTest {
|
|||
Config.configData = ConfigData(url = "http://example.com", objectMapper = jacksonObjectMapper())
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
auth(mock(), mock(), mock())
|
||||
}
|
||||
}
|
||||
client.get("/auth-check").apply {
|
||||
assertEquals(HttpStatusCode.Unauthorized, call.response.status)
|
||||
|
@ -155,7 +169,10 @@ class SecurityKtTest {
|
|||
Config.configData = ConfigData(url = "http://example.com", objectMapper = jacksonObjectMapper())
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
auth(mock(), mock(), mock())
|
||||
}
|
||||
}
|
||||
client.get("/auth-check") {
|
||||
header("Authorization", "Digest dsfjjhogalkjdfmlhaog")
|
||||
|
@ -172,7 +189,10 @@ class SecurityKtTest {
|
|||
Config.configData = ConfigData(url = "http://example.com", objectMapper = jacksonObjectMapper())
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
auth(mock(), mock(), mock())
|
||||
}
|
||||
}
|
||||
client.get("/auth-check") {
|
||||
header("Authorization", "")
|
||||
|
@ -190,7 +210,10 @@ class SecurityKtTest {
|
|||
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
auth(mock(), mock(), mock())
|
||||
}
|
||||
}
|
||||
client.get("/auth-check") {
|
||||
header("Authorization", "Bearer ")
|
||||
|
@ -244,11 +267,12 @@ class SecurityKtTest {
|
|||
)
|
||||
)
|
||||
}
|
||||
val userRepository = mock<IUserRepository>()
|
||||
val jwtService = mock<IJwtService>()
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), metaService, userRepository, jwtService, jwkProvider)
|
||||
configureSecurity(jwkProvider, metaService)
|
||||
routing {
|
||||
auth(mock(), mock(), mock())
|
||||
}
|
||||
}
|
||||
|
||||
client.get("/auth-check") {
|
||||
|
@ -304,11 +328,12 @@ class SecurityKtTest {
|
|||
)
|
||||
)
|
||||
}
|
||||
val userRepository = mock<IUserRepository>()
|
||||
val jwtService = mock<IJwtService>()
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), metaService, userRepository, jwtService, jwkProvider)
|
||||
configureSecurity(jwkProvider, metaService)
|
||||
routing {
|
||||
auth(mock(), mock(), mock())
|
||||
}
|
||||
}
|
||||
client.get("/auth-check") {
|
||||
header("Authorization", "Bearer $token")
|
||||
|
@ -362,11 +387,12 @@ class SecurityKtTest {
|
|||
)
|
||||
)
|
||||
}
|
||||
val userRepository = mock<IUserRepository>()
|
||||
val jwtService = mock<IJwtService>()
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), metaService, userRepository, jwtService, jwkProvider)
|
||||
configureSecurity(jwkProvider, metaService)
|
||||
routing {
|
||||
auth(mock(), mock(), mock())
|
||||
}
|
||||
}
|
||||
client.get("/auth-check") {
|
||||
header("Authorization", "Bearer $token")
|
||||
|
@ -420,11 +446,12 @@ class SecurityKtTest {
|
|||
)
|
||||
)
|
||||
}
|
||||
val userRepository = mock<IUserRepository>()
|
||||
val jwtService = mock<IJwtService>()
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), metaService, userRepository, jwtService, jwkProvider)
|
||||
configureSecurity(jwkProvider, metaService)
|
||||
routing {
|
||||
auth(mock(), mock(), mock())
|
||||
}
|
||||
}
|
||||
client.get("/auth-check") {
|
||||
header("Authorization", "Bearer $token")
|
||||
|
@ -477,11 +504,12 @@ class SecurityKtTest {
|
|||
)
|
||||
)
|
||||
}
|
||||
val userRepository = mock<IUserRepository>()
|
||||
val jwtService = mock<IJwtService>()
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), metaService, userRepository, jwtService, jwkProvider)
|
||||
configureSecurity(jwkProvider, metaService)
|
||||
routing {
|
||||
auth(mock(), mock(), mock())
|
||||
}
|
||||
}
|
||||
client.get("/auth-check") {
|
||||
header("Authorization", "Bearer $token")
|
||||
|
@ -501,7 +529,10 @@ class SecurityKtTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), jwtService, mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
auth(mock(), mock(), jwtService)
|
||||
}
|
||||
}
|
||||
client.post("/refresh-token") {
|
||||
header("Content-Type", "application/json")
|
||||
|
@ -523,7 +554,10 @@ class SecurityKtTest {
|
|||
application {
|
||||
configureStatusPages()
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), jwtService, mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
auth(mock(), mock(), jwtService)
|
||||
}
|
||||
}
|
||||
client.post("/refresh-token") {
|
||||
header("Content-Type", "application/json")
|
||||
|
|
|
@ -4,6 +4,8 @@ import com.auth0.jwt.interfaces.Claim
|
|||
import com.auth0.jwt.interfaces.Payload
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import dev.usbharu.hideout.config.Config
|
||||
import dev.usbharu.hideout.domain.model.hideout.dto.PostResponse
|
||||
import dev.usbharu.hideout.domain.model.hideout.dto.UserResponse
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.Visibility
|
||||
import dev.usbharu.hideout.plugins.TOKEN_AUTH
|
||||
|
@ -32,18 +34,27 @@ class PostsTest {
|
|||
environment {
|
||||
config = ApplicationConfig("empty.conf")
|
||||
}
|
||||
val user = UserResponse(
|
||||
id = 54321,
|
||||
name = "user1",
|
||||
domain = "example.com",
|
||||
screenName = "user 1",
|
||||
description = "Test user",
|
||||
url = "https://example.com/users/54321",
|
||||
createdAt = Instant.now().toEpochMilli()
|
||||
)
|
||||
val posts = listOf(
|
||||
Post(
|
||||
PostResponse(
|
||||
id = 12345,
|
||||
userId = 4321,
|
||||
user = user,
|
||||
text = "test1",
|
||||
visibility = Visibility.PUBLIC,
|
||||
createdAt = Instant.now().toEpochMilli(),
|
||||
url = "https://example.com/posts/1"
|
||||
),
|
||||
Post(
|
||||
PostResponse(
|
||||
id = 123456,
|
||||
userId = 4322,
|
||||
user = user,
|
||||
text = "test2",
|
||||
visibility = Visibility.PUBLIC,
|
||||
createdAt = Instant.now().toEpochMilli(),
|
||||
|
@ -64,7 +75,7 @@ class PostsTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
posts(postService)
|
||||
|
@ -89,27 +100,35 @@ class PostsTest {
|
|||
val payload = mock<Payload> {
|
||||
on { getClaim(eq("uid")) } doReturn claim
|
||||
}
|
||||
|
||||
val user = UserResponse(
|
||||
id = 54321,
|
||||
name = "user1",
|
||||
domain = "example.com",
|
||||
screenName = "user 1",
|
||||
description = "Test user",
|
||||
url = "https://example.com/users/54321",
|
||||
createdAt = Instant.now().toEpochMilli()
|
||||
)
|
||||
val posts = listOf(
|
||||
Post(
|
||||
PostResponse(
|
||||
id = 12345,
|
||||
userId = 4321,
|
||||
user = user,
|
||||
text = "test1",
|
||||
visibility = Visibility.PUBLIC,
|
||||
createdAt = Instant.now().toEpochMilli(),
|
||||
url = "https://example.com/posts/1"
|
||||
),
|
||||
Post(
|
||||
PostResponse(
|
||||
id = 123456,
|
||||
userId = 4322,
|
||||
user = user,
|
||||
text = "test2",
|
||||
visibility = Visibility.PUBLIC,
|
||||
createdAt = Instant.now().toEpochMilli(),
|
||||
url = "https://example.com/posts/2"
|
||||
),
|
||||
Post(
|
||||
PostResponse(
|
||||
id = 1234567,
|
||||
userId = 4333,
|
||||
user = user,
|
||||
text = "Followers only",
|
||||
visibility = Visibility.FOLLOWERS,
|
||||
createdAt = Instant.now().toEpochMilli(),
|
||||
|
@ -156,9 +175,18 @@ class PostsTest {
|
|||
environment {
|
||||
config = ApplicationConfig("empty.conf")
|
||||
}
|
||||
val post = Post(
|
||||
12345,
|
||||
1234,
|
||||
val user = UserResponse(
|
||||
id = 54321,
|
||||
name = "user1",
|
||||
domain = "example.com",
|
||||
screenName = "user 1",
|
||||
description = "Test user",
|
||||
url = "https://example.com/users/54321",
|
||||
createdAt = Instant.now().toEpochMilli()
|
||||
)
|
||||
val post = PostResponse(
|
||||
id = 12345,
|
||||
user = user,
|
||||
text = "aaa",
|
||||
visibility = Visibility.PUBLIC,
|
||||
createdAt = Instant.now().toEpochMilli(),
|
||||
|
@ -169,7 +197,7 @@ class PostsTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
posts(postService)
|
||||
|
@ -187,9 +215,17 @@ class PostsTest {
|
|||
environment {
|
||||
config = ApplicationConfig("empty.conf")
|
||||
}
|
||||
val post = Post(
|
||||
val post = PostResponse(
|
||||
12345,
|
||||
1234,
|
||||
UserResponse(
|
||||
id = 54321,
|
||||
name = "user1",
|
||||
domain = "example.com",
|
||||
screenName = "user 1",
|
||||
description = "Test user",
|
||||
url = "https://example.com/users/54321",
|
||||
createdAt = Instant.now().toEpochMilli()
|
||||
),
|
||||
text = "aaa",
|
||||
visibility = Visibility.FOLLOWERS,
|
||||
createdAt = Instant.now().toEpochMilli(),
|
||||
|
@ -242,14 +278,22 @@ class PostsTest {
|
|||
onBlocking { createPost(any(), any()) } doAnswer {
|
||||
val argument = it.getArgument<dev.usbharu.hideout.domain.model.hideout.form.Post>(0)
|
||||
val userId = it.getArgument<Long>(1)
|
||||
Post(
|
||||
123L,
|
||||
userId,
|
||||
null,
|
||||
argument.text,
|
||||
Instant.now().toEpochMilli(),
|
||||
Visibility.PUBLIC,
|
||||
"https://example.com"
|
||||
PostResponse(
|
||||
id = 123L,
|
||||
user = UserResponse(
|
||||
id = 54321,
|
||||
name = "user1",
|
||||
domain = "example.com",
|
||||
screenName = "user 1",
|
||||
description = "Test user",
|
||||
url = "https://example.com/users/54321",
|
||||
createdAt = Instant.now().toEpochMilli()
|
||||
),
|
||||
overview = null,
|
||||
text = argument.text,
|
||||
createdAt = Instant.now().toEpochMilli(),
|
||||
visibility = Visibility.PUBLIC,
|
||||
url = "https://example.com"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -290,18 +334,27 @@ class PostsTest {
|
|||
environment {
|
||||
config = ApplicationConfig("empty.conf")
|
||||
}
|
||||
val user = UserResponse(
|
||||
id = 54321,
|
||||
name = "user1",
|
||||
domain = "example.com",
|
||||
screenName = "user 1",
|
||||
description = "Test user",
|
||||
url = "https://example.com/users/54321",
|
||||
createdAt = Instant.now().toEpochMilli()
|
||||
)
|
||||
val posts = listOf(
|
||||
Post(
|
||||
PostResponse(
|
||||
id = 12345,
|
||||
userId = 1,
|
||||
user = user,
|
||||
text = "test1",
|
||||
visibility = Visibility.PUBLIC,
|
||||
createdAt = Instant.now().toEpochMilli(),
|
||||
url = "https://example.com/posts/1"
|
||||
),
|
||||
Post(
|
||||
PostResponse(
|
||||
id = 123456,
|
||||
userId = 1,
|
||||
user = user,
|
||||
text = "test2",
|
||||
visibility = Visibility.PUBLIC,
|
||||
createdAt = Instant.now().toEpochMilli(),
|
||||
|
@ -323,7 +376,7 @@ class PostsTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
posts(postService)
|
||||
|
@ -342,18 +395,27 @@ class PostsTest {
|
|||
environment {
|
||||
config = ApplicationConfig("empty.conf")
|
||||
}
|
||||
val user = UserResponse(
|
||||
id = 54321,
|
||||
name = "user1",
|
||||
domain = "example.com",
|
||||
screenName = "user 1",
|
||||
description = "Test user",
|
||||
url = "https://example.com/users/54321",
|
||||
createdAt = Instant.now().toEpochMilli()
|
||||
)
|
||||
val posts = listOf(
|
||||
Post(
|
||||
PostResponse(
|
||||
id = 12345,
|
||||
userId = 1,
|
||||
user = user,
|
||||
text = "test1",
|
||||
visibility = Visibility.PUBLIC,
|
||||
createdAt = Instant.now().toEpochMilli(),
|
||||
url = "https://example.com/posts/1"
|
||||
),
|
||||
Post(
|
||||
PostResponse(
|
||||
id = 123456,
|
||||
userId = 1,
|
||||
user = user,
|
||||
text = "test2",
|
||||
visibility = Visibility.PUBLIC,
|
||||
createdAt = Instant.now().toEpochMilli(),
|
||||
|
@ -375,7 +437,7 @@ class PostsTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
posts(postService)
|
||||
|
@ -394,18 +456,27 @@ class PostsTest {
|
|||
environment {
|
||||
config = ApplicationConfig("empty.conf")
|
||||
}
|
||||
val user = UserResponse(
|
||||
id = 54321,
|
||||
name = "user1",
|
||||
domain = "example.com",
|
||||
screenName = "user 1",
|
||||
description = "Test user",
|
||||
url = "https://example.com/users/54321",
|
||||
createdAt = Instant.now().toEpochMilli()
|
||||
)
|
||||
val posts = listOf(
|
||||
Post(
|
||||
PostResponse(
|
||||
id = 12345,
|
||||
userId = 1,
|
||||
user = user,
|
||||
text = "test1",
|
||||
visibility = Visibility.PUBLIC,
|
||||
createdAt = Instant.now().toEpochMilli(),
|
||||
url = "https://example.com/posts/1"
|
||||
),
|
||||
Post(
|
||||
PostResponse(
|
||||
id = 123456,
|
||||
userId = 1,
|
||||
user = user,
|
||||
text = "test2",
|
||||
visibility = Visibility.PUBLIC,
|
||||
createdAt = Instant.now().toEpochMilli(),
|
||||
|
@ -427,7 +498,7 @@ class PostsTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
posts(postService)
|
||||
|
@ -446,18 +517,27 @@ class PostsTest {
|
|||
environment {
|
||||
config = ApplicationConfig("empty.conf")
|
||||
}
|
||||
val user = UserResponse(
|
||||
id = 54321,
|
||||
name = "user1",
|
||||
domain = "example.com",
|
||||
screenName = "user 1",
|
||||
description = "Test user",
|
||||
url = "https://example.com/users/54321",
|
||||
createdAt = Instant.now().toEpochMilli()
|
||||
)
|
||||
val posts = listOf(
|
||||
Post(
|
||||
PostResponse(
|
||||
id = 12345,
|
||||
userId = 1,
|
||||
user = user,
|
||||
text = "test1",
|
||||
visibility = Visibility.PUBLIC,
|
||||
createdAt = Instant.now().toEpochMilli(),
|
||||
url = "https://example.com/posts/1"
|
||||
),
|
||||
Post(
|
||||
PostResponse(
|
||||
id = 123456,
|
||||
userId = 1,
|
||||
user = user,
|
||||
text = "test2",
|
||||
visibility = Visibility.PUBLIC,
|
||||
createdAt = Instant.now().toEpochMilli(),
|
||||
|
@ -479,7 +559,7 @@ class PostsTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
posts(postService)
|
||||
|
@ -498,9 +578,17 @@ class PostsTest {
|
|||
environment {
|
||||
config = ApplicationConfig("empty.conf")
|
||||
}
|
||||
val post = Post(
|
||||
val post = PostResponse(
|
||||
id = 123456,
|
||||
userId = 1,
|
||||
user = UserResponse(
|
||||
id = 54321,
|
||||
name = "user1",
|
||||
domain = "example.com",
|
||||
screenName = "user 1",
|
||||
description = "Test user",
|
||||
url = "https://example.com/users/54321",
|
||||
createdAt = Instant.now().toEpochMilli()
|
||||
),
|
||||
text = "test2",
|
||||
visibility = Visibility.PUBLIC,
|
||||
createdAt = Instant.now().toEpochMilli(),
|
||||
|
@ -511,7 +599,7 @@ class PostsTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
posts(postService)
|
||||
|
@ -530,9 +618,17 @@ class PostsTest {
|
|||
environment {
|
||||
config = ApplicationConfig("empty.conf")
|
||||
}
|
||||
val post = Post(
|
||||
val post = PostResponse(
|
||||
id = 123456,
|
||||
userId = 1,
|
||||
user = UserResponse(
|
||||
id = 54321,
|
||||
name = "user1",
|
||||
domain = "example.com",
|
||||
screenName = "user 1",
|
||||
description = "Test user",
|
||||
url = "https://example.com/users/54321",
|
||||
createdAt = Instant.now().toEpochMilli()
|
||||
),
|
||||
text = "test2",
|
||||
visibility = Visibility.PUBLIC,
|
||||
createdAt = Instant.now().toEpochMilli(),
|
||||
|
@ -543,7 +639,7 @@ class PostsTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
posts(postService)
|
||||
|
@ -562,9 +658,17 @@ class PostsTest {
|
|||
environment {
|
||||
config = ApplicationConfig("empty.conf")
|
||||
}
|
||||
val post = Post(
|
||||
val post = PostResponse(
|
||||
id = 123456,
|
||||
userId = 1,
|
||||
user = UserResponse(
|
||||
id = 54321,
|
||||
name = "user1",
|
||||
domain = "example.com",
|
||||
screenName = "user 1",
|
||||
description = "Test user",
|
||||
url = "https://example.com/users/54321",
|
||||
createdAt = Instant.now().toEpochMilli()
|
||||
),
|
||||
text = "test2",
|
||||
visibility = Visibility.PUBLIC,
|
||||
createdAt = Instant.now().toEpochMilli(),
|
||||
|
@ -575,7 +679,7 @@ class PostsTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
posts(postService)
|
||||
|
@ -594,9 +698,17 @@ class PostsTest {
|
|||
environment {
|
||||
config = ApplicationConfig("empty.conf")
|
||||
}
|
||||
val post = Post(
|
||||
val post = PostResponse(
|
||||
id = 123456,
|
||||
userId = 1,
|
||||
user = UserResponse(
|
||||
id = 54321,
|
||||
name = "user1",
|
||||
domain = "example.com",
|
||||
screenName = "user 1",
|
||||
description = "Test user",
|
||||
url = "https://example.com/users/54321",
|
||||
createdAt = Instant.now().toEpochMilli()
|
||||
),
|
||||
text = "test2",
|
||||
visibility = Visibility.PUBLIC,
|
||||
createdAt = Instant.now().toEpochMilli(),
|
||||
|
@ -607,7 +719,7 @@ class PostsTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
posts(postService)
|
||||
|
|
|
@ -58,7 +58,7 @@ class UsersTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
users(mock(), userService)
|
||||
|
@ -96,7 +96,7 @@ class UsersTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
users(userService, mock())
|
||||
|
@ -127,7 +127,7 @@ class UsersTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
users(userService, mock())
|
||||
|
@ -162,7 +162,7 @@ class UsersTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
users(mock(), userApiService)
|
||||
|
@ -195,7 +195,7 @@ class UsersTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
users(mock(), userApiService)
|
||||
|
@ -228,7 +228,7 @@ class UsersTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
users(mock(), userApiService)
|
||||
|
@ -261,7 +261,7 @@ class UsersTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
users(mock(), userApiService)
|
||||
|
@ -306,7 +306,7 @@ class UsersTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
users(mock(), userApiService)
|
||||
|
@ -351,7 +351,7 @@ class UsersTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
users(mock(), userApiService)
|
||||
|
@ -396,7 +396,7 @@ class UsersTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
users(mock(), userApiService)
|
||||
|
@ -591,7 +591,7 @@ class UsersTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
users(mock(), userApiService)
|
||||
|
@ -636,7 +636,7 @@ class UsersTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
users(mock(), userApiService)
|
||||
|
@ -681,7 +681,7 @@ class UsersTest {
|
|||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), mock(), mock())
|
||||
configureSecurity(mock(), mock())
|
||||
routing {
|
||||
route("/api/internal/v1") {
|
||||
users(mock(), userApiService)
|
||||
|
|
|
@ -48,13 +48,21 @@ class ActivityPubReceiveFollowServiceImplTest {
|
|||
firstValue.invoke(scheduleContext, ReceiveFollowJob)
|
||||
val actor = scheduleContext.props.props[ReceiveFollowJob.actor.name]
|
||||
val targetActor = scheduleContext.props.props[ReceiveFollowJob.targetActor.name]
|
||||
val follow = scheduleContext.props.props[ReceiveFollowJob.follow.name]
|
||||
val follow = scheduleContext.props.props[ReceiveFollowJob.follow.name] as String
|
||||
assertEquals("https://follower.example.com", actor)
|
||||
assertEquals("https://example.com", targetActor)
|
||||
//language=JSON
|
||||
assertEquals(
|
||||
"""{"type":"Follow","name":"Follow","actor":"https://follower.example.com","object":"https://example.com","@context":null}""",
|
||||
follow
|
||||
Json.parseToJsonElement(
|
||||
"""{
|
||||
"type": "Follow",
|
||||
"name": "Follow",
|
||||
"actor": "https://follower.example.com",
|
||||
"object": "https://example.com",
|
||||
"@context": null
|
||||
}"""
|
||||
),
|
||||
Json.parseToJsonElement(follow)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -155,7 +163,14 @@ class ActivityPubReceiveFollowServiceImplTest {
|
|||
data = mapOf<String, Any>(
|
||||
ReceiveFollowJob.actor.name to "https://follower.example.com",
|
||||
ReceiveFollowJob.targetActor.name to "https://example.com",
|
||||
ReceiveFollowJob.follow.name to """{"type":"Follow","name":"Follow","object":"https://example.com","actor":"https://follower.example.com","@context":null}"""
|
||||
//language=JSON
|
||||
ReceiveFollowJob.follow.name to """{
|
||||
"type": "Follow",
|
||||
"name": "Follow",
|
||||
"object": "https://example.com",
|
||||
"actor": "https://follower.example.com",
|
||||
"@context": null
|
||||
}"""
|
||||
),
|
||||
json = Json
|
||||
)
|
||||
|
|
|
@ -1,21 +1,24 @@
|
|||
import { defineConfig } from 'vite';
|
||||
import {defineConfig, splitVendorChunkPlugin} from 'vite';
|
||||
import solidPlugin from 'vite-plugin-solid';
|
||||
import suidPlugin from "@suid/vite-plugin";
|
||||
import visualizer from "rollup-plugin-visualizer";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [solidPlugin(),suidPlugin()],
|
||||
plugins: [solidPlugin(),suidPlugin(),splitVendorChunkPlugin()],
|
||||
server: {
|
||||
port: 3000,
|
||||
proxy: {
|
||||
'/api': 'http://localhost:8080',
|
||||
'/login': 'http://localhost:8080',
|
||||
'/auth-check': 'http://localhost:8080',
|
||||
'/refresh-token': 'http://localhost:8080',
|
||||
}
|
||||
},
|
||||
root: './src/main/web',
|
||||
build: {
|
||||
target: 'esnext',
|
||||
outDir: '../resources/static',
|
||||
rollupOptions:{
|
||||
plugins: [
|
||||
visualizer()
|
||||
]
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue