1
0
forked from SPC/spc-site
This commit is contained in:
Alexander Nozik 2022-05-01 21:14:00 +03:00
parent a334f91ea7
commit bafbf200f2
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
11 changed files with 138 additions and 71 deletions

View File

@ -1,4 +1,3 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import ru.mipt.npm.gradle.KScienceVersions import ru.mipt.npm.gradle.KScienceVersions
plugins { plugins {
@ -21,11 +20,11 @@ application {
applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment") applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment")
} }
tasks.withType<KotlinCompile>{ //tasks.withType<KotlinCompile>{
kotlinOptions{ // kotlinOptions{
freeCompilerArgs = freeCompilerArgs + "-Xcontext-receivers" // freeCompilerArgs = freeCompilerArgs + "-Xcontext-receivers"
} // }
} //}
val dataforgeVersion by extra("0.6.0-dev-3") val dataforgeVersion by extra("0.6.0-dev-3")
val ktorVersion = KScienceVersions.ktorVersion val ktorVersion = KScienceVersions.ktorVersion

View File

@ -16,12 +16,12 @@ import io.ktor.server.routing.route
import io.ktor.server.routing.routing import io.ktor.server.routing.routing
import ru.mipt.plugins.configureTemplating import ru.mipt.plugins.configureTemplating
import ru.mipt.spc.magprog.DataSetSiteContext import ru.mipt.spc.magprog.DataSetSiteContext
import ru.mipt.spc.magprog.DirectoryDataTree
import ru.mipt.spc.magprog.SiteContext import ru.mipt.spc.magprog.SiteContext
import ru.mipt.spc.magprog.magProgPage import ru.mipt.spc.magprog.magProgPage
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.dataforge.io.io import space.kscience.dataforge.io.io
import space.kscience.dataforge.io.yaml.YamlPlugin import space.kscience.dataforge.io.yaml.YamlPlugin
import space.kscience.snark.DirectoryDataTree
import java.nio.file.Path import java.nio.file.Path

View File

@ -0,0 +1,12 @@
package ru.mipt
//private fun snapshotRoute(route: Route, path: Path){
// route.children.forEach {
// it.
// }
//}
//
//
//fun Application.snapshotTo(path: Path): Job = launch{
// pluginOrNull(Routing)?.children
//}

View File

@ -7,7 +7,6 @@ import kotlinx.serialization.json.Json
import org.intellij.markdown.flavours.commonmark.CommonMarkFlavourDescriptor import org.intellij.markdown.flavours.commonmark.CommonMarkFlavourDescriptor
import org.intellij.markdown.html.HtmlGenerator import org.intellij.markdown.html.HtmlGenerator
import org.intellij.markdown.parser.MarkdownParser import org.intellij.markdown.parser.MarkdownParser
import ru.mipt.spc.magprog.DirectoryDataTree.Companion.META_FILE_EXTENSION_KEY
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.dataforge.data.* import space.kscience.dataforge.data.*
import space.kscience.dataforge.io.asBinary import space.kscience.dataforge.io.asBinary
@ -19,6 +18,7 @@ import space.kscience.dataforge.meta.string
import space.kscience.dataforge.meta.toMeta import space.kscience.dataforge.meta.toMeta
import space.kscience.dataforge.misc.DFInternal import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.snark.DirectoryDataTree.Companion.META_FILE_EXTENSION_KEY
import kotlin.reflect.KType import kotlin.reflect.KType
import kotlin.reflect.full.isSubtypeOf import kotlin.reflect.full.isSubtypeOf
import kotlin.reflect.typeOf import kotlin.reflect.typeOf
@ -35,12 +35,12 @@ class DataSetSiteContext(
private val markdownParser = MarkdownParser(markdownFlavor) private val markdownParser = MarkdownParser(markdownFlavor)
//TODO replace by a plugin //TODO replace by a plugin
private suspend fun Data<ByteArray>.toHtmlBlock(): HtmlBlock { private suspend fun Data<ByteArray>.toHtmlBlock(): HtmlData {
val fileType = meta[META_FILE_EXTENSION_KEY].string val fileType = meta[META_FILE_EXTENSION_KEY].string
val src = await().decodeToString() val src = await().decodeToString()
return when (fileType) { return when (fileType) {
"html" -> HtmlBlock(meta) { "html" -> HtmlData(meta) {
div { div {
unsafe { unsafe {
+src +src
@ -48,7 +48,7 @@ class DataSetSiteContext(
} }
} }
"markdown", "mdown", "mkdn", "mkd", "md" -> HtmlBlock(meta) { "markdown", "mdown", "mkdn", "mkd", "md" -> HtmlData(meta) {
div("markdown") { div("markdown") {
val parsedTree = markdownParser.buildMarkdownTreeFromString(src) val parsedTree = markdownParser.buildMarkdownTreeFromString(src)
@ -93,11 +93,11 @@ class DataSetSiteContext(
override fun <T : Any> resolveAll(type: KType, filter: (name: Name, meta: Meta) -> Boolean): DataSet<T> = override fun <T : Any> resolveAll(type: KType, filter: (name: Name, meta: Meta) -> Boolean): DataSet<T> =
dataSet.select(type, filter = filter) dataSet.select(type, filter = filter)
override fun resolveHtml(name: Name): HtmlBlock? = runBlocking { override fun resolveHtml(name: Name): HtmlData? = runBlocking {
resolve<ByteArray>(name)?.takeIf { it.published }?.toHtmlBlock() resolve<ByteArray>(name)?.takeIf { it.published }?.toHtmlBlock()
} }
override fun resolveAllHtml(filter: (name: Name, meta: Meta) -> Boolean): Map<Name, HtmlBlock> = runBlocking { override fun resolveAllHtml(filter: (name: Name, meta: Meta) -> Boolean): Map<Name, HtmlData> = runBlocking {
buildMap { buildMap {
resolveAll<ByteArray>(filter).dataSequence().filter { it.published }.forEach { resolveAll<ByteArray>(filter).dataSequence().filter { it.published }.forEach {
put(it.name, it.toHtmlBlock()) put(it.name, it.toHtmlBlock())

View File

@ -1,25 +0,0 @@
package ru.mipt.spc.magprog
import kotlinx.html.FlowContent
import space.kscience.dataforge.meta.*
enum class Language {
EN,
RU
}
interface HtmlBlock {
val meta: Meta
val content: FlowContent.() -> Unit
}
fun HtmlBlock(meta: Meta, content: FlowContent.() -> Unit ) = object: HtmlBlock{
override val meta: Meta = meta
override val content: FlowContent.() -> Unit = content
}
val HtmlBlock.id: String get() = meta["id"]?.string ?: "block[${hashCode()}]"
val HtmlBlock.language: Language get() = meta["language"]?.enum<Language>() ?: Language.RU
val HtmlBlock.order: Int? get() = meta["order"]?.int

View File

@ -0,0 +1,34 @@
package ru.mipt.spc.magprog
import kotlinx.coroutines.runBlocking
import kotlinx.html.FlowContent
import kotlinx.html.TagConsumer
import space.kscience.dataforge.data.Data
import space.kscience.dataforge.data.await
import space.kscience.dataforge.meta.*
enum class Language {
EN,
RU
}
//TODO replace by VisionForge type
typealias HtmlFragment = TagConsumer<*>.() -> Unit
typealias HtmlData = Data<HtmlFragment>
fun HtmlData(meta: Meta, content: TagConsumer<*>.() -> Unit): HtmlData = Data(content, meta)
val HtmlData.id: String get() = meta["id"]?.string ?: "block[${hashCode()}]"
val HtmlData.language: Language get() = meta["language"]?.enum<Language>() ?: Language.RU
val HtmlData.order: Int? get() = meta["order"]?.int
fun TagConsumer<*>.htmlData(data: HtmlData) = runBlocking {
data.await().invoke(this@htmlData)
}
fun FlowContent.htmlData(data: HtmlData) = runBlocking {
data.await().invoke(consumer)
}

View File

@ -4,7 +4,7 @@ import kotlinx.css.*
import kotlinx.html.* import kotlinx.html.*
import space.kscience.dataforge.meta.string import space.kscience.dataforge.meta.string
class Person(val block: HtmlBlock) : HtmlBlock by block { class Person(val block: HtmlData) : HtmlData by block {
val name: String by meta.string { error("Mentor name is not defined") } val name: String by meta.string { error("Mentor name is not defined") }
val photo: String? by meta.string() val photo: String? by meta.string()
} }
@ -27,7 +27,7 @@ private fun FlowContent.personCards(list: List<Person>, prefix: String) {
h2 { h2 {
a(href = "#${prefix}_${mentor.id}") { +mentor.name } a(href = "#${prefix}_${mentor.id}") { +mentor.name }
} }
with(mentor) { content() } htmlData(mentor.block)
} }
} }
} }

View File

@ -28,12 +28,12 @@ interface SiteContext: ContextAware {
/** /**
* Resolve a Html builder by its full name * Resolve a Html builder by its full name
*/ */
fun resolveHtml(name: Name): HtmlBlock? fun resolveHtml(name: Name): HtmlData?
/** /**
* Find all Html blocks using given name/meta filter * Find all Html blocks using given name/meta filter
*/ */
fun resolveAllHtml(filter: (name: Name, meta: Meta) -> Boolean): Map<Name, HtmlBlock> fun resolveAllHtml(filter: (name: Name, meta: Meta) -> Boolean): Map<Name, HtmlData>
} }
@OptIn(DFInternal::class) @OptIn(DFInternal::class)

View File

@ -6,8 +6,10 @@ import kotlinx.html.*
import space.kscience.dataforge.data.await import space.kscience.dataforge.data.await
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.getIndexed
import space.kscience.dataforge.meta.string import space.kscience.dataforge.meta.string
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.plus
//fun CssBuilder.magProgCss() { //fun CssBuilder.magProgCss() {
@ -26,9 +28,9 @@ class MagProgSection(
val id: String, val id: String,
val title: String, val title: String,
val style: String, val style: String,
override val content: FlowContent.() -> Unit, val content: FlowContent.() -> Unit,
) : HtmlBlock { ) {
override val meta: Meta val meta: Meta
get() = Meta { get() = Meta {
"id" put id "id" put id
"title" put title "title" put title
@ -47,13 +49,14 @@ private fun wrapSection(
} }
private fun wrapSection( private fun wrapSection(
block: HtmlBlock, block: HtmlData,
idOverride: String? = null, idOverride: String? = null,
): MagProgSection = wrapSection( ): MagProgSection = wrapSection(
idOverride ?: block.id, idOverride ?: block.id,
block.meta["section_title"]?.string ?: error("Section without title"), block.meta["section_title"]?.string ?: error("Section without title"),
block.content ){
) htmlData(block)
}
private val CONTENT_NODE_NAME = Name.EMPTY//"content".asName() private val CONTENT_NODE_NAME = Name.EMPTY//"content".asName()
private val INTRO_PATH: Name = CONTENT_NODE_NAME + "intro" private val INTRO_PATH: Name = CONTENT_NODE_NAME + "intro"
@ -68,7 +71,7 @@ context(SiteContext) private fun FlowContent.programSection() {
val recommendedBlock = resolveHtml(RECOMMENDED_COURSES_PATH)!! val recommendedBlock = resolveHtml(RECOMMENDED_COURSES_PATH)!!
div("inner") { div("inner") {
h2 { +"Учебная программа" } h2 { +"Учебная программа" }
with(programBlock) { content() } htmlData(programBlock)
button(classes = "fit btn btn-primary btn-lg") { button(classes = "fit btn btn-primary btn-lg") {
attributes["data-bs-toggle"] = "collapse" attributes["data-bs-toggle"] = "collapse"
attributes["data-bs-target"] = "#recommended-courses-collapse-text" attributes["data-bs-target"] = "#recommended-courses-collapse-text"
@ -79,7 +82,7 @@ context(SiteContext) private fun FlowContent.programSection() {
div("collapse pt-3") { div("collapse pt-3") {
id = "recommended-courses-collapse-text" id = "recommended-courses-collapse-text"
div("card card-body") { div("card card-body") {
with(recommendedBlock) { content() } htmlData(recommendedBlock)
} }
} }
} }
@ -91,7 +94,7 @@ context(SiteContext) private fun FlowContent.partners() {
div("inner") { div("inner") {
h2 { +"Партнеры" } h2 { +"Партнеры" }
div("features") { div("features") {
partnersData.items.values.forEach { partner -> partnersData.getIndexed("content".asName()).values.forEach { partner ->
section { section {
a(href = partner["link"].string, target = "_blank") { a(href = partner["link"].string, target = "_blank") {
rel = "noreferrer" rel = "noreferrer"
@ -205,7 +208,7 @@ context(SiteContext) fun HTML.magProgPage() {
id = "footer" id = "footer"
div("inner") { div("inner") {
ul("menu") { ul("menu") {
li { +"""&copy; Untitled. All rights reserved.""" } li { +"""&copy; SPC. All rights reserved.""" }
li { li {
+"""Design:""" +"""Design:"""
a { a {

View File

@ -1,9 +1,8 @@
package ru.mipt.spc.magprog package space.kscience.snark
import space.kscience.dataforge.data.Data import space.kscience.dataforge.data.Data
import space.kscience.dataforge.data.DataTree import space.kscience.dataforge.data.DataTree
import space.kscience.dataforge.data.DataTreeItem import space.kscience.dataforge.data.DataTreeItem
import space.kscience.dataforge.data.StaticData
import space.kscience.dataforge.io.IOPlugin import space.kscience.dataforge.io.IOPlugin
import space.kscience.dataforge.io.readEnvelopeFile import space.kscience.dataforge.io.readEnvelopeFile
import space.kscience.dataforge.io.readMetaFile import space.kscience.dataforge.io.readMetaFile
@ -21,22 +20,6 @@ import kotlin.io.path.nameWithoutExtension
import kotlin.reflect.KType import kotlin.reflect.KType
import kotlin.reflect.typeOf import kotlin.reflect.typeOf
//internal object ByteArrayIOFormat : IOFormat<ByteArray> {
//
// override val type: KType = typeOf<ByteArray>()
//
// override fun writeObject(output: Output, obj: ByteArray) {
// output.writeFully(obj)
// }
//
// override fun readObject(input: Input): ByteArray = input.readBytes()
//
// override fun toMeta(): Meta = Meta {
// IOFormat.NAME_KEY put "ByteArray"
// }
//
//}
class DirectoryDataTree(val io: IOPlugin, val path: Path) : DataTree<ByteArray> { class DirectoryDataTree(val io: IOPlugin, val path: Path) : DataTree<ByteArray> {
override val dataType: KType override val dataType: KType
@ -51,7 +34,9 @@ class DirectoryDataTree(val io: IOPlugin, val path: Path) : DataTree<ByteArray>
META_FILE_EXTENSION_KEY put filePath.extension META_FILE_EXTENSION_KEY put filePath.extension
//TODO add other file information //TODO add other file information
} }
return StaticData(typeOf<ByteArray>(), envelope.data?.toByteArray() ?: ByteArray(0), meta) return Data(meta){
envelope.data?.toByteArray() ?: ByteArray(0)
}
} }

View File

@ -0,0 +1,59 @@
package space.kscience.snark
import io.ktor.http.ContentType
import space.kscience.dataforge.actions.Action
import space.kscience.dataforge.actions.map
import space.kscience.dataforge.context.*
import space.kscience.dataforge.io.yaml.YamlPlugin
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.string
import space.kscience.dataforge.misc.Type
import space.kscience.dataforge.names.Name
import kotlin.reflect.KClass
import kotlin.reflect.KType
@Type(SnarkParser.TYPE)
interface SnarkParser<R : Any> {
val contentType: ContentType
val fileExtensions: Set<String>
val priority: Int
val resultType: KType
suspend fun parse(bytes: ByteArray): R
companion object {
const val TYPE = "snark.parser"
}
}
class SnarkPlugin : AbstractPlugin() {
val yaml by require(YamlPlugin)
val io get() = yaml.io
override val tag: PluginTag get() = Companion.tag
private val parsers: Map<Name, SnarkParser<*>> by lazy { context.gather(SnarkParser.TYPE, true) }
private val parseAction = Action.map<ByteArray, Any> {
result { bytes ->
parsers.values.filter { parser ->
parser.contentType.toString() == meta["contentType"].string ||
meta[DirectoryDataTree.META_FILE_EXTENSION_KEY].string in parser.fileExtensions
}.maxByOrNull {
it.priority
}?.parse(bytes) ?: bytes
}
}
companion object : PluginFactory<SnarkPlugin> {
override val tag: PluginTag = PluginTag("snark")
override val type: KClass<out SnarkPlugin> = SnarkPlugin::class
override fun build(context: Context, meta: Meta): SnarkPlugin = SnarkPlugin()
}
}