Skip to content

Commit

Permalink
Merge pull request #24 from blogify-dev/dev
Browse files Browse the repository at this point in the history
Merge dev into master for v0.1.0
  • Loading branch information
ranile authored Nov 13, 2019
2 parents 20f6b09 + 357b41e commit b99eaae
Show file tree
Hide file tree
Showing 64 changed files with 1,356 additions and 437 deletions.
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ FROM openjdk:10-jre

WORKDIR /var/server/

ADD build/dist/jar/blogify-PRX2-all.jar .
ADD build/dist/jar/blogify-0.1.0-all.jar .

EXPOSE 8080
EXPOSE 5005

CMD ["java", "-server", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseG1GC", "-XX:MaxGCPauseMillis=100", "-XX:+UseStringDeduplication", "-jar", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005", "blogify-PRX2-all.jar"]
CMD ["java", "-server", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseG1GC", "-XX:MaxGCPauseMillis=100", "-XX:+UseStringDeduplication", "-jar", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005", "blogify-0.1.0-all.jar"]
9 changes: 8 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ plugins {
}

group = "blogify"
version = "PRX2"
version = "0.1.0"

application {
mainClassName = "io.ktor.server.netty.EngineMain"
Expand Down Expand Up @@ -46,6 +46,13 @@ dependencies {
compile("io.ktor:ktor-auth-jwt:$ktor_version")
compile("io.ktor:ktor-jackson:$ktor_version")

// Ktor client

compile("io.ktor:ktor-client-cio:$ktor_version")
compile("io.ktor:ktor-client-json:$ktor_version")
compile("io.ktor:ktor-client-json-jvm:$ktor_version")
compile("io.ktor:ktor-client-jackson:$ktor_version")

// Database stuff

compile("org.postgresql:postgresql:$pg_driver_version")
Expand Down
10 changes: 10 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ services:
- '5005:5005'
depends_on:
- db
- ts
volumes:
- 'static-data:/var/static/'
db:
Expand All @@ -15,7 +16,16 @@ services:
- '5432:5432'
volumes:
- 'db-data:/var/lib/postgresql/data'
ts:
image: 'typesense/typesense:0.11.0'
ports:
- '8108:8108'
volumes:
- 'ts-data:/data'
command:
--data-dir /data --api-key=Hu52dwsas2AdxdE

volumes:
db-data:
static-data:
ts-data:
73 changes: 67 additions & 6 deletions src/blogify/backend/Application.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import blogify.backend.routes.auth
import blogify.backend.database.handling.query
import blogify.backend.resources.models.Resource
import blogify.backend.routes.static
import blogify.backend.search.Typesense
import blogify.backend.util.SinglePageApplication

import io.ktor.application.call
Expand All @@ -40,12 +41,10 @@ import io.ktor.routing.routing
import org.jetbrains.exposed.sql.SchemaUtils

import kotlinx.coroutines.runBlocking
import org.jetbrains.exposed.sql.update

import org.slf4j.event.Level
import java.util.UUID

const val version = "PRX4"
const val version = "0.1.0"

const val asciiLogo = """
__ __ _ ____
Expand All @@ -57,7 +56,9 @@ const val asciiLogo = """
---- Version $version - Development build -
"""

fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)
fun main(args: Array<String>) {
io.ktor.server.netty.EngineMain.main(args)
}

@Suppress("unused") // Referenced in application.conf
@kotlin.jvm.JvmOverloads
Expand Down Expand Up @@ -105,7 +106,7 @@ fun Application.mainModule(@Suppress("UNUSED_PARAMETER") testing: Boolean = fals
// Default headers

install(DefaultHeaders) {
header("Server", "blogify-core PRX4")
header("Server", "blogify-core $version")
header("X-Powered-By", "Ktor 1.2.3")
}

Expand Down Expand Up @@ -136,7 +137,67 @@ fun Application.mainModule(@Suppress("UNUSED_PARAMETER") testing: Boolean = fals
Users,
Comments,
Uploadables
)
).also {
val articleJson = """
{
"name": "articles",
"fields": [
{
"name": "title",
"type": "string"
},
{
"name": "createdAt",
"type": "float"
},
{
"name": "createdBy",
"type": "string"
},
{
"name": "content",
"type": "string"
},
{
"name": "summary",
"type": "string"
},
{
"name": "categories",
"type": "string[]",
"facet": true
}
],
"default_sorting_field": "createdAt"
}
""".trimIndent()
val userJson = """{
"name": "users",
"fields": [
{
"name": "username",
"type": "string"
},
{
"name": "name",
"type": "string"
},
{
"name": "email",
"type": "string"
},
{
"name": "dsf_jank",
"type": "int32"
}
],
"default_sorting_field": "dsf_jank"
}""".trimIndent()

Typesense.submitResourceTemplate(articleJson)
Typesense.submitResourceTemplate(userJson)

}
}}

// Initialize routes
Expand Down
2 changes: 1 addition & 1 deletion src/blogify/backend/annotations/check.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ import org.intellij.lang.annotations.Language
@MustBeDocumented
annotation class check (
@Language(value = "RegExp") val pattern: String
)
)
3 changes: 3 additions & 0 deletions src/blogify/backend/database/Database.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import com.zaxxer.hikari.HikariDataSource

import org.jetbrains.exposed.sql.Database

/**
* Meta object regrouping setup and utility functions for PostgreSQL.
*/
object Database {

lateinit var instance: Database
Expand Down
7 changes: 3 additions & 4 deletions src/blogify/backend/database/Tables.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,17 @@ import blogify.backend.services.UserService
import blogify.backend.services.articles.CommentService
import blogify.backend.services.models.Service

import com.github.kittinunf.result.coroutines.SuspendableResult

import io.ktor.application.ApplicationCall
import io.ktor.http.ContentType
import org.jetbrains.exposed.sql.Column

import org.jetbrains.exposed.sql.ReferenceOption.*
import org.jetbrains.exposed.sql.ResultRow
import org.jetbrains.exposed.sql.Table
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction

import com.github.kittinunf.result.coroutines.SuspendableResult

abstract class ResourceTable<R : Resource> : Table() {

abstract suspend fun convert(callContext: ApplicationCall, source: ResultRow): SuspendableResult<R, Service.Exception.Fetching>
Expand All @@ -34,7 +33,7 @@ abstract class ResourceTable<R : Resource> : Table() {

object Articles : ResourceTable<Article>() {

val title: Column<String> = varchar ("title", 512)
val title = varchar ("title", 512)
val createdAt = long ("created_at")
val createdBy = uuid ("created_by").references(Users.uuid, onDelete = SET_NULL)
val content = text ("content")
Expand Down
14 changes: 8 additions & 6 deletions src/blogify/backend/resources/Article.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonIdentityReference
import com.fasterxml.jackson.annotation.ObjectIdGenerators

import blogify.backend.annotations.check
import blogify.backend.annotations.noslice
import blogify.backend.database.Articles
import blogify.backend.resources.models.Resource
import blogify.backend.database.handling.query
Expand All @@ -16,11 +17,12 @@ import java.util.*
/**
* Represents an Article [Resource].
*
* @property title The title of the [Article].
* @property createdAt The time of creation of the [Article], in `UNIX` timestamp format.
* @property createdBy The UUID of the [User] author of the article.
* @property content The [Content][Article.Content] of the article. Not included in the JSON serialization.
* @property title The title of the [Article].
* @property createdAt The time of creation of the [Article], in `UNIX` timestamp format.
* @property createdBy The UUID of the [User] author of the article.
* @property content The content of the article.
* @property summary The summary of the article.
* @property categories The [categories][Article.Category] of the article.
*/
@JsonIdentityInfo (
scope = Article::class,
Expand All @@ -29,7 +31,7 @@ import java.util.*
property = "uuid"
)
data class Article (
val title: @check("\\w+") String,
val title: @check("^.{0,512}") String,

val createdAt: Long = Date().time,

Expand Down
3 changes: 1 addition & 2 deletions src/blogify/backend/resources/User.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package blogify.backend.resources

import blogify.backend.annotations.check
import blogify.backend.resources.models.Resource
import blogify.backend.resources.static.models.StaticResourceHandle
import blogify.backend.annotations.noslice
Expand All @@ -22,7 +21,7 @@ data class User (
@noslice val password: String, // IMPORTANT : DO NOT EVER REMOVE THIS ANNOTATION !
val name: String,
val email: String,
val profilePicture: @type("image/png") StaticResourceHandle,
val profilePicture: @type("image/*") StaticResourceHandle,

override val uuid: UUID = UUID.randomUUID()
) : Resource(uuid)
108 changes: 108 additions & 0 deletions src/blogify/backend/resources/search/Search.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package blogify.backend.resources.search

import blogify.backend.resources.Article
import blogify.backend.resources.User
import blogify.backend.services.UserService
import io.ktor.application.ApplicationCall
import java.util.*

/**
* Models for deserializing json returned by typesense
*
* @author hamza1311
*/
data class Search<H> (
val facet_counts: List<Any>?, // |\
val found: Int?, // | Will not appear on no results
val hits: List<Hit<H>>?, // |/
val page: Int,
val search_time_ms: Int
) {
data class Hit<D>(
val document: D,
val highlights: List<Highlight>
)

/**
* Model representing an [article][Article] hit returned by typesense
*/
data class ArticleDocument(
val categories: List<String>,
val content: String,
val createdAt: Double,
val createdBy: UUID,
val summary: String,
val title: String,
val id: UUID
) {

/**
* Convert [ArticleDocument] to [Article].
* It constructs the [article][Article] object using the properties of the given [document][ArticleDocument]
* It does **NOT** makes a database call
*
* @return The article object created by properties of the given [document][ArticleDocument]
*/
suspend fun article(): Article = Article(
title = title,
content = content,
summary = summary,
createdBy = UserService.get(id = createdBy).get(),
categories = categories.map { Article.Category(it) },
createdAt = createdAt.toLong(),
uuid = id
)
}

/**
* Model representing an [user][User] hit returned by typesense
*
* @param dsf_jank This is a workaround for `default_sorting_field` parameter in typesense, which is a required parameter whose value can only be a `float` or `int32`. Its value is always `0` in our case
*/
data class UserDocument(
val username: String,
val name: String,
val email: String,
val dsf_jank: Int,
val id: UUID
) {

/**
* Convert [UserDocument] to [User].
* It constructs the [user][User] object by fetcting user with uuid of [id] from [users][blogify.backend.database.Users] table
* This is a database call
*
* @return The user object with uuid of [id]
*/
suspend fun user(callContext: ApplicationCall): User = UserService.get(callContext, id).get()
}

data class Highlight(
val `field`: String,
val snippet: String
)
}

/**
* Constructs [Search.ArticleDocument] from [Article]
*/
fun Article.asDocument(): Search.ArticleDocument = Search.ArticleDocument(
title = this.title,
content = this.content,
summary = this.summary,
createdBy = this.createdBy.uuid,
categories = this.categories.map { it.name },
createdAt = this.createdAt.toDouble(),
id = this.uuid
)

/**
* Constructs [Search.UserDocument] from [User]
*/
fun User.asDocument(): Search.UserDocument = Search.UserDocument(
username = this.username,
name = this.name,
email = this.email,
dsf_jank = 0,
id = this.uuid
)
Loading

0 comments on commit b99eaae

Please sign in to comment.