init here
This commit is contained in:
101
исх/бд/скуля/скуля.tri
Normal file
101
исх/бд/скуля/скуля.tri
Normal file
@@ -0,0 +1,101 @@
|
||||
модуль скуля
|
||||
осторожно // cognitohazard!
|
||||
|
||||
импорт "стд::вывод"
|
||||
импорт "исх/спринтф"
|
||||
импорт "исх/строка"
|
||||
импорт "исх/форматы/джесон"
|
||||
|
||||
// c:include "sckulya.h"
|
||||
|
||||
фн tri_sqlite_open(файл: Строка, оплошность := Строка): Цел64 @внеш
|
||||
фн tri_sqlite_close(бд: Цел64): Цел64 @внеш
|
||||
фн tri_sqlite_exec(бд: Цел64, прошение: Строка, оплошность := Строка) @внеш
|
||||
фн tri_sqlite_query(бд: Цел64, прошение: Строка, результат := Строка, оплошность := Строка): Цел64 @внеш
|
||||
|
||||
тип Картотека* = класс {
|
||||
ручка: Цел64 := -1
|
||||
}
|
||||
|
||||
фн открыть картотеку*(путь: Строка): Картотека {
|
||||
пусть оплошность := ""
|
||||
пусть ручка = tri_sqlite_open(путь, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
авария(спринтф.ф("не удалось открыть картотеку: $стр", оплошность))
|
||||
}
|
||||
|
||||
вернуть Картотека{
|
||||
ручка: ручка
|
||||
}
|
||||
}
|
||||
|
||||
фн (к: Картотека) закрыть*() {
|
||||
пусть код = tri_sqlite_close(к.ручка)
|
||||
|
||||
если код # 0 {
|
||||
авария(спринтф.ф("не удалось закрыть картотеку, код $цел", код))
|
||||
}
|
||||
}
|
||||
|
||||
фн (к: Картотека) выполнить*(прошение: Строка, оплошность := Строка) {
|
||||
tri_sqlite_exec(к.ручка, прошение, оплошность)
|
||||
}
|
||||
|
||||
фн (к: Картотека) запросить*(прошение: Строка, оплошность := Строка): джесон.ДжесонМногоЗначений {
|
||||
пусть результат := ""
|
||||
пусть код = tri_sqlite_query(к.ручка, прошение, результат, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть джесон.ДжесонМногоЗначений{}
|
||||
}
|
||||
|
||||
пусть объект = джесон.парсить(спринтф.ф("{\"данные\": $стр}", результат), оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть джесон.ДжесонМногоЗначений{}
|
||||
}
|
||||
|
||||
вернуть объект.значения[0].значение(:джесон.ДжесонМногоЗначений)
|
||||
}
|
||||
|
||||
тип Аргумент = класс {
|
||||
|
||||
}
|
||||
|
||||
фн экранировать(т аргумента: Слово64, аргумент: *): Строка {
|
||||
пусть кек = аргумент(:Слово64)
|
||||
|
||||
если т аргумента = тег(Строка) {
|
||||
пусть знач = кек(:осторожно Строка)
|
||||
|
||||
вернуть спринтф.ф("'$стр'", строка.заменить(знач, "'", "''"))
|
||||
}
|
||||
|
||||
если т аргумента = тег(Цел64) {
|
||||
пусть знач = кек(:осторожно Цел64)
|
||||
вернуть спринтф.ф("$цел", знач)
|
||||
}
|
||||
|
||||
авария("неподдерживаемый тип аргумента")
|
||||
}
|
||||
|
||||
фн (к: Картотека) запросить безопасно*(прошение: Строка, оплошность := Строка, аргументы: ...*): джесон.ДжесонМногоЗначений {
|
||||
пусть части прошения = строка.разобрать(прошение, "?")
|
||||
|
||||
если длина(части прошения) - 1 # длина(аргументы) {
|
||||
авария("число аргументов не совпадает с числом подстановок")
|
||||
}
|
||||
|
||||
пусть собранное прошение := ""
|
||||
|
||||
пусть ай := 0
|
||||
пока ай < длина(аргументы) {
|
||||
собранное прошение := строка.собрать(собранное прошение, части прошения[ай], экранировать(тег(аргументы[ай]), нечто(аргументы[ай])))
|
||||
ай++
|
||||
}
|
||||
|
||||
собранное прошение := строка.собрать(собранное прошение, части прошения[ай])
|
||||
|
||||
вернуть к.запросить(собранное прошение, оплошность)
|
||||
}
|
||||
28
исх/бюрократия/бюрократия.tri
Normal file
28
исх/бюрократия/бюрократия.tri
Normal file
@@ -0,0 +1,28 @@
|
||||
модуль бюрократия
|
||||
|
||||
импорт "исх/строка"
|
||||
импорт "исх/сеть/хттп"
|
||||
|
||||
тип Паспорт* = класс {
|
||||
имя пользователя*: Строка := ""
|
||||
пароль*: Строка := ""
|
||||
}
|
||||
|
||||
фн получить данные паспорта*(обращение: хттп.ХттпОбращение): мб Паспорт {
|
||||
цикл [номер]заглавие среди обращение.заглавия {
|
||||
если заглавие.имя = "Authorization" {
|
||||
пусть части = строка.разобрать(заглавие.значение, " ")
|
||||
|
||||
если длина(части) # 3 | части[0] # "Basic" {
|
||||
вернуть пусто
|
||||
}
|
||||
|
||||
вернуть Паспорт{
|
||||
имя пользователя: части[1],
|
||||
пароль: части[2],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
вернуть пусто
|
||||
}
|
||||
18
исх/властелины/главный/главный.tri
Normal file
18
исх/властелины/главный/главный.tri
Normal file
@@ -0,0 +1,18 @@
|
||||
модуль главный
|
||||
|
||||
импорт "исх/массивы"
|
||||
импорт "исх/сеть/хттп"
|
||||
импорт "исх/сеть/хттп/маршрутизатор"
|
||||
|
||||
фн главный*(путь: Строка, параметры: массивы.Строки, обращение: маршрутизатор.Обращение): хттп.ХттпОтвет {
|
||||
вернуть хттп.ХттпОтвет{
|
||||
туловище: "Привет, мир!",
|
||||
}
|
||||
}
|
||||
|
||||
фн добавить маршруты*(маршрутизатор: маршрутизатор.Маршрутизатор): маршрутизатор.Маршрутизатор {
|
||||
маршрутизатор.добавить маршрут("/api/", массивы.Строки["GET"], главный)
|
||||
|
||||
вернуть маршрутизатор
|
||||
}
|
||||
|
||||
373
исх/властелины/классы/классы.tri
Normal file
373
исх/властелины/классы/классы.tri
Normal file
@@ -0,0 +1,373 @@
|
||||
модуль классы
|
||||
|
||||
импорт "стд::вывод"
|
||||
импорт "исх/строка"
|
||||
импорт "исх/спринтф"
|
||||
импорт "исх/массивы"
|
||||
импорт "исх/сеть/хттп"
|
||||
импорт "исх/форматы/джесон"
|
||||
импорт "исх/сеть/хттп/маршрутизатор"
|
||||
импорт "исх/картотека"
|
||||
импорт "исх/картотека/репозитории"
|
||||
импорт "исх/бюрократия"
|
||||
|
||||
фн список классов*(путь: Строка, параметры: массивы.Строки, обращение: маршрутизатор.Обращение): хттп.ХттпОтвет {
|
||||
пусть оплошность := ""
|
||||
пусть картотека = картотека.зайти()
|
||||
пусть пользователь = репозитории.авторизовать по паспорту(бюрократия.получить данные паспорта(обращение), оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если пользователь = пусто {
|
||||
вернуть хттп.ответ_401()
|
||||
}
|
||||
|
||||
пусть учитель = репозитории.пользователь учитель(пользователь^.идентификатор, оплошность)
|
||||
пусть админ = репозитории.пользователь админ(пользователь^.идентификатор, оплошность)
|
||||
|
||||
если учитель = пусто & ~админ {
|
||||
вернуть хттп.ответ_403()
|
||||
}
|
||||
|
||||
пусть фильтр по учителю := -1
|
||||
|
||||
пусть параметр учитель = обращение.запрос-в-пути.найти("учитель")
|
||||
|
||||
если параметр учитель # пусто {
|
||||
пусть номер байта := 0
|
||||
строка.извлечь цел(параметр учитель^.значение, номер байта, фильтр по учителю)
|
||||
} иначе если ~админ {
|
||||
фильтр по учителю := учитель^.идентификатор
|
||||
}
|
||||
|
||||
если фильтр по учителю = -1 {
|
||||
вернуть хттп.ответ_400()
|
||||
}
|
||||
|
||||
пусть классы := картотека.запросить безопасно(`
|
||||
SELECT id, number, letter, creator_teacher_id
|
||||
FROM classes
|
||||
WHERE creator_teacher_id = ?
|
||||
`, оплошность, фильтр по учителю)
|
||||
|
||||
пусть джесон ответ = джесон.ДжесонМногоЗначений{}
|
||||
|
||||
цикл [номер телефона мамы]клass среди классы.значения {
|
||||
пусть объект = клass(:джесон.ДжесонОбъект)
|
||||
|
||||
пусть идентификатор = объект.получить("id").число()^.значение
|
||||
пусть номер = объект.получить("number").число()^.значение
|
||||
пусть буква = объект.получить("letter").строка()^
|
||||
пусть создатель = объект.получить("creator_teacher_id").число()^.значение
|
||||
|
||||
пусть джесон клass = джесон.ДжесонОбъект{}
|
||||
джесон клass.вставить("идентификатор", джесон.ДжесонЧисло{ значение: идентификатор })
|
||||
джесон клass.вставить("номер", джесон.ДжесонЧисло{ значение: номер })
|
||||
джесон клass.вставить("буква", джесон.ДжесонСтрока{ значение: буква })
|
||||
джесон клass.вставить("создатель", джесон.ДжесонЧисло{ значение: создатель })
|
||||
|
||||
джесон ответ.значения.добавить(джесон клass)
|
||||
}
|
||||
|
||||
пусть туловище = джесон.сериализовать(джесон.ДжесонОбъект{
|
||||
значения: джесон.ДжесонКлючЗначения[
|
||||
джесон.ДжесонКлючЗначение{
|
||||
ключ: "классы",
|
||||
значение: джесон ответ
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
вернуть хттп.ХттпОтвет{
|
||||
туловище: туловище
|
||||
}
|
||||
}
|
||||
|
||||
фн создать клass*(путь: Строка, параметры: массивы.Строки, обращение: маршрутизатор.Обращение): хттп.ХттпОтвет {
|
||||
пусть оплошность := ""
|
||||
пусть картотека = картотека.зайти()
|
||||
|
||||
пусть пользователь = репозитории.авторизовать по паспорту(бюрократия.получить данные паспорта(обращение), оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если пользователь = пусто {
|
||||
вернуть хттп.ответ_401()
|
||||
}
|
||||
|
||||
пусть учитель = репозитории.пользователь учитель(пользователь^.идентификатор, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если учитель = пусто {
|
||||
вернуть хттп.ответ_403()
|
||||
}
|
||||
|
||||
|
||||
пусть данные = джесон.парсить(обращение.туловище, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_400()
|
||||
}
|
||||
|
||||
пусть номер := данные.получить("номер").число()
|
||||
пусть буква := данные.получить("буква").строка()
|
||||
|
||||
если номер = пусто | буква = пусто {
|
||||
вернуть хттп.ответ_400()
|
||||
}
|
||||
|
||||
|
||||
пусть ответ = картотека.запросить безопасно(`
|
||||
INSERT INTO classes (number, letter, creator_teacher_id)
|
||||
VALUES (?, ?, ?)
|
||||
RETURNING id, number, letter, creator_teacher_id
|
||||
`, оплошность, номер^.значение, буква^, учитель^.идентификатор)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_422()
|
||||
}
|
||||
|
||||
если длина(ответ.значения) = 0 {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
пусть созданный = ответ.значения[0](:джесон.ДжесонОбъект)
|
||||
пусть идентификатор = созданный.получить("id").число()^.значение
|
||||
пусть создан номер = созданный.получить("number").число()^.значение
|
||||
пусть создан буква = созданный.получить("letter").строка()^
|
||||
пусть создан создатель = созданный.получить("creator_teacher_id").число()^.значение
|
||||
|
||||
пусть тело = джесон.сериализовать(джесон.ДжесонОбъект{
|
||||
значения: джесон.ДжесонКлючЗначения[
|
||||
джесон.ДжесонКлючЗначение{ключ: "идентификатор", значение: джесон.ДжесонЧисло{значение: идентификатор}},
|
||||
джесон.ДжесонКлючЗначение{ключ: "номер", значение: джесон.ДжесонЧисло{значение: создан номер}},
|
||||
джесон.ДжесонКлючЗначение{ключ: "буква", значение: джесон.ДжесонСтрока{значение: создан буква}},
|
||||
джесон.ДжесонКлючЗначение{ключ: "создатель", значение: джесон.ДжесонЧисло{значение: создан создатель}}
|
||||
]
|
||||
})
|
||||
|
||||
вернуть хттп.создать ответ(
|
||||
хттп.ответ_201(),
|
||||
хттп.ХттпОтвет{туловище: тело}
|
||||
)
|
||||
}
|
||||
|
||||
фн удалить клass*(путь: Строка, параметры: массивы.Строки, обращение: маршрутизатор.Обращение): хттп.ХттпОтвет {
|
||||
пусть оплошность := ""
|
||||
пусть картотека = картотека.зайти()
|
||||
|
||||
пусть пользователь = репозитории.авторизовать по паспорту(бюрократия.получить данные паспорта(обращение), оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если пользователь = пусто {
|
||||
вернуть хттп.ответ_401()
|
||||
}
|
||||
|
||||
пусть учитель = репозитории.пользователь учитель(пользователь^.идентификатор, оплошность)
|
||||
пусть админ = репозитории.пользователь админ(пользователь^.идентификатор, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если учитель = пусто & ~админ {
|
||||
вернуть хттп.ответ_403()
|
||||
}
|
||||
|
||||
если длина(параметры) < 1 {
|
||||
вернуть хттп.ответ_400()
|
||||
}
|
||||
|
||||
пусть ид класса = параметры[0]
|
||||
|
||||
пусть ответ := джесон.ДжесонМногоЗначений{}
|
||||
|
||||
если админ {
|
||||
ответ := картотека.запросить безопасно(`
|
||||
DELETE FROM classes WHERE id = ?
|
||||
RETURNING id
|
||||
`, оплошность, ид класса)
|
||||
} иначе {
|
||||
ответ := картотека.запросить безопасно(`
|
||||
DELETE FROM classes WHERE id = ? AND creator_teacher_id = ?
|
||||
RETURNING id
|
||||
`, оплошность, ид класса, учитель^.идентификатор)
|
||||
}
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если длина(ответ.значения) = 0 {
|
||||
вывод.ф("Класс с id = $стр не найден или не принадлежит учителю", ид класса)
|
||||
вернуть хттп.ответ_404()
|
||||
}
|
||||
|
||||
вернуть хттп.ответ_204()
|
||||
}
|
||||
|
||||
фн добавить ученика в клass*(путь: Строка, параметры: массивы.Строки, обращение: маршрутизатор.Обращение): хттп.ХттпОтвет {
|
||||
пусть оплошность := ""
|
||||
пусть картотека = картотека.зайти()
|
||||
|
||||
пусть пользователь = репозитории.авторизовать по паспорту(бюрократия.получить данные паспорта(обращение), оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если пользователь = пусто {
|
||||
вернуть хттп.ответ_401()
|
||||
}
|
||||
|
||||
пусть учитель = репозитории.пользователь учитель(пользователь^.идентификатор, оплошность)
|
||||
пусть админ = репозитории.пользователь админ(пользователь^.идентификатор, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если учитель = пусто & ~админ {
|
||||
вернуть хттп.ответ_403()
|
||||
}
|
||||
|
||||
если длина(параметры) < 2 {
|
||||
вернуть хттп.ответ_400()
|
||||
}
|
||||
|
||||
пусть ид класса = параметры[0]
|
||||
пусть ид ученика = параметры[1]
|
||||
|
||||
пусть клass := джесон.ДжесонМногоЗначений{}
|
||||
|
||||
если админ {
|
||||
клass := картотека.запросить безопасно(`
|
||||
SELECT id FROM classes WHERE id = ?
|
||||
`, оплошность, ид класса)
|
||||
} иначе {
|
||||
клass := картотека.запросить безопасно(`
|
||||
SELECT id FROM classes WHERE id = ? AND creator_teacher_id = ?
|
||||
`, оплошность, ид класса, учитель^.идентификатор)
|
||||
}
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если длина(клass.значения) = 0 {
|
||||
вернуть хттп.ответ_403()
|
||||
}
|
||||
|
||||
пусть ученик = картотека.запросить безопасно(`
|
||||
SELECT id FROM students WHERE id = ?
|
||||
`, оплошность, ид ученика)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если длина(ученик.значения) = 0 {
|
||||
вернуть хттп.ответ_404()
|
||||
}
|
||||
|
||||
пусть ответ = картотека.запросить безопасно(`
|
||||
INSERT INTO class_students (class_id, student_id)
|
||||
VALUES (?, ?)
|
||||
RETURNING id
|
||||
`, оплошность, ид класса, ид ученика)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_422()
|
||||
}
|
||||
|
||||
вернуть хттп.ответ_201()
|
||||
}
|
||||
|
||||
фн удалить ученика из класса*(путь: Строка, параметры: массивы.Строки, обращение: маршрутизатор.Обращение): хттп.ХттпОтвет {
|
||||
пусть оплошность := ""
|
||||
пусть картотека = картотека.зайти()
|
||||
|
||||
пусть пользователь = репозитории.авторизовать по паспорту(бюрократия.получить данные паспорта(обращение), оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если пользователь = пусто {
|
||||
вернуть хттп.ответ_401()
|
||||
}
|
||||
|
||||
пусть учитель = репозитории.пользователь учитель(пользователь^.идентификатор, оплошность)
|
||||
пусть админ = репозитории.пользователь админ(пользователь^.идентификатор, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если учитель = пусто & ~админ {
|
||||
вернуть хттп.ответ_403()
|
||||
}
|
||||
|
||||
если длина(параметры) < 2 {
|
||||
вернуть хттп.ответ_400()
|
||||
}
|
||||
|
||||
пусть ид класса = параметры[0]
|
||||
пусть ид ученика = параметры[1]
|
||||
|
||||
пусть клass := джесон.ДжесонМногоЗначений{}
|
||||
|
||||
если админ {
|
||||
клass := картотека.запросить безопасно(`
|
||||
SELECT id FROM classes WHERE id = ?
|
||||
`, оплошность, ид класса)
|
||||
} иначе {
|
||||
клass := картотека.запросить безопасно(`
|
||||
SELECT id FROM classes WHERE id = ? AND creator_teacher_id = ?
|
||||
`, оплошность, ид класса, учитель^.идентификатор)
|
||||
}
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если длина(клass.значения) = 0 {
|
||||
вернуть хттп.ответ_403()
|
||||
}
|
||||
|
||||
пусть ответ = картотека.запросить безопасно(`
|
||||
DELETE FROM class_students
|
||||
WHERE class_id = ? AND student_id = ?
|
||||
RETURNING id
|
||||
`, оплошность, ид класса, ид ученика)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если длина(ответ.значения) = 0 {
|
||||
вернуть хттп.ответ_404()
|
||||
}
|
||||
|
||||
вернуть хттп.ответ_204()
|
||||
}
|
||||
|
||||
фн добавить маршруты*(маршрутизатор: маршрутизатор.Маршрутизатор): маршрутизатор.Маршрутизатор {
|
||||
маршрутизатор.добавить маршрут("/api/classes", массивы.Строки["GET"], список классов)
|
||||
маршрутизатор.добавить маршрут("/api/classes", массивы.Строки["POST"], создать клass)
|
||||
маршрутизатор.добавить маршрут("/api/classes/$", массивы.Строки["DELETE"], удалить клass)
|
||||
маршрутизатор.добавить маршрут("/api/classes/$/students/$", массивы.Строки["POST"], добавить ученика в клass)
|
||||
маршрутизатор.добавить маршрут("/api/classes/$/students/$", массивы.Строки["DELETE"], удалить ученика из класса)
|
||||
|
||||
вернуть маршрутизатор
|
||||
}
|
||||
84
исх/властелины/пользователи/пользователи.tri
Normal file
84
исх/властелины/пользователи/пользователи.tri
Normal file
@@ -0,0 +1,84 @@
|
||||
модуль пользователи
|
||||
|
||||
импорт "стд::вывод"
|
||||
импорт "исх/строка"
|
||||
импорт "исх/спринтф"
|
||||
импорт "исх/массивы"
|
||||
импорт "исх/сеть/хттп"
|
||||
импорт "исх/форматы/джесон"
|
||||
импорт "исх/сеть/хттп/маршрутизатор"
|
||||
импорт "исх/картотека"
|
||||
импорт "исх/картотека/репозитории"
|
||||
импорт "исх/бюрократия"
|
||||
|
||||
фн войти*(путь: Строка, параметры: массивы.Строки, обращение: маршрутизатор.Обращение): хттп.ХттпОтвет {
|
||||
пусть картотека = картотека.зайти()
|
||||
пусть оплошность := ""
|
||||
пусть данные = джесон.парсить(обращение.туловище, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
пусть имя пользователя := данные.получить("имя пользователя").строка()
|
||||
пусть пароль := данные.получить("пароль").строка()
|
||||
|
||||
пусть пользователь = репозитории.авторизовать пользователя(имя пользователя^, пароль^, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вывод.ф("$стр\n", оплошность)
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если пользователь = пусто {
|
||||
вернуть хттп.ответ_401()
|
||||
}
|
||||
|
||||
вернуть хттп.ХттпОтвет{
|
||||
туловище: "Рады видеть вас снова :3"
|
||||
}
|
||||
}
|
||||
|
||||
фн сменить пароль*(путь: Строка, параметры: массивы.Строки, обращение: маршрутизатор.Обращение): хттп.ХттпОтвет {
|
||||
пусть оплошность := ""
|
||||
пусть картотека = картотека.зайти()
|
||||
пусть пользователь = репозитории.авторизовать по паспорту(бюрократия.получить данные паспорта(обращение), оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если пользователь = пусто {
|
||||
вернуть хттп.ответ_401()
|
||||
}
|
||||
|
||||
пусть данные = джесон.парсить(обращение.туловище, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_400()
|
||||
}
|
||||
|
||||
пусть новый пароль := данные.получить("новый пароль").строка()
|
||||
|
||||
если новый пароль = пусто | новый пароль^ = "" {
|
||||
вернуть хттп.ответ_422()
|
||||
}
|
||||
|
||||
картотека.запросить безопасно(`
|
||||
UPDATE users SET password = ? WHERE id = ?
|
||||
`, оплошность, новый пароль^, пользователь^.идентификатор
|
||||
)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
вернуть хттп.ответ_204()
|
||||
}
|
||||
|
||||
фн добавить маршруты*(маршрутизатор: маршрутизатор.Маршрутизатор): маршрутизатор.Маршрутизатор {
|
||||
маршрутизатор.добавить маршрут("/api/users/login", массивы.Строки["POST"], войти)
|
||||
маршрутизатор.добавить маршрут("/api/users/password", массивы.Строки["PUT"], сменить пароль)
|
||||
|
||||
вернуть маршрутизатор
|
||||
}
|
||||
381
исх/властелины/пользователи/ученики/ученики.tri
Normal file
381
исх/властелины/пользователи/ученики/ученики.tri
Normal file
@@ -0,0 +1,381 @@
|
||||
модуль ученики
|
||||
|
||||
импорт "стд::вывод"
|
||||
импорт "исх/строка"
|
||||
импорт "исх/спринтф"
|
||||
импорт "исх/массивы"
|
||||
импорт "исх/сеть/хттп"
|
||||
импорт "исх/форматы/джесон"
|
||||
импорт "исх/сеть/хттп/маршрутизатор"
|
||||
импорт "исх/картотека"
|
||||
импорт "исх/картотека/репозитории"
|
||||
импорт "исх/бюрократия"
|
||||
|
||||
фн создать*(путь: Строка, параметры: массивы.Строки, обращение: маршрутизатор.Обращение): хттп.ХттпОтвет {
|
||||
пусть оплошность := ""
|
||||
пусть картотека = картотека.зайти()
|
||||
|
||||
пусть пользователь = репозитории.авторизовать по паспорту(бюрократия.получить данные паспорта(обращение), оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если пользователь = пусто {
|
||||
вернуть хттп.ответ_401()
|
||||
}
|
||||
|
||||
пусть учитель = репозитории.пользователь учитель(пользователь^.идентификатор, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если учитель = пусто {
|
||||
вернуть хттп.ответ_403()
|
||||
}
|
||||
|
||||
пусть данные = джесон.парсить(обращение.туловище, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_400()
|
||||
}
|
||||
|
||||
пусть имя := данные.получить("имя").строка()
|
||||
пусть фамилия := данные.получить("фамилия").строка()
|
||||
пусть отчество := данные.получить("отчество").строка()
|
||||
пусть пароль := данные.получить("пароль").строка()
|
||||
пусть повтор пароля := данные.получить("повтор пароля").строка()
|
||||
|
||||
пусть снилс := данные.получить("снилс").строка()
|
||||
пусть паспорт := данные.получить("паспорт").строка()
|
||||
|
||||
если имя = пусто | фамилия = пусто | отчество = пусто | пароль = пусто | повтор пароля = пусто | снилс = пусто | паспорт = пусто {
|
||||
вернуть хттп.ответ_400()
|
||||
}
|
||||
|
||||
если имя^ = "" | фамилия^ = "" | отчество^ = "" | пароль^ = "" | повтор пароля^ = "" | снилс^ = "" | паспорт^ = "" {
|
||||
вернуть хттп.ответ_400()
|
||||
}
|
||||
|
||||
если пароль^ # повтор пароля^ {
|
||||
вернуть хттп.создать ответ(
|
||||
хттп.ответ_400(),
|
||||
хттп.ХттпОтвет{ туловище: "Пароли не совпадают." }
|
||||
)
|
||||
}
|
||||
|
||||
пусть имя пользователя = спринтф.ф("$стр.$стр", имя^, фамилия^)
|
||||
|
||||
пусть ответ = картотека.запросить безопасно(`
|
||||
INSERT INTO users (first_name, last_name, middle_name, username, password)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
RETURNING id
|
||||
`, оплошность, имя^, фамилия^, отчество^, имя пользователя, пароль^)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если длина(ответ.значения) = 0 {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
пусть айди пользователя = ответ.значения[0](:джесон.ДжесонОбъект).получить("id").число()
|
||||
|
||||
если айди пользователя = пусто {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
пусть ученик = картотека.запросить безопасно(`
|
||||
INSERT INTO students (user_id, mentor_id, snils, passport)
|
||||
VALUES (?, ?, ?, ?)
|
||||
RETURNING id
|
||||
`, оплошность,
|
||||
айди пользователя^.значение,
|
||||
учитель^.идентификатор,
|
||||
снилс^,
|
||||
паспорт^
|
||||
)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если длина(ученик.значения) = 0 {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
пусть созданный = ученик.значения[0](:джесон.ДжесонОбъект)
|
||||
пусть идентификатор ученика = созданный.получить("id").число()
|
||||
|
||||
если идентификатор ученика = пусто {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
пусть тело = джесон.сериализовать(джесон.ДжесонОбъект{
|
||||
значения: джесон.ДжесонКлючЗначения[
|
||||
джесон.ДжесонКлючЗначение{ ключ: "идентификатор", значение: джесон.ДжесонЧисло{ значение: идентификатор ученика^.значение } },
|
||||
джесон.ДжесонКлючЗначение{ ключ: "имя", значение: джесон.ДжесонСтрока{ значение: имя^ } },
|
||||
джесон.ДжесонКлючЗначение{ ключ: "фамилия", значение: джесон.ДжесонСтрока{ значение: фамилия^ } },
|
||||
джесон.ДжесонКлючЗначение{ ключ: "отчество", значение: джесон.ДжесонСтрока{ значение: отчество^ } },
|
||||
джесон.ДжесонКлючЗначение{ ключ: "снилс", значение: джесон.ДжесонСтрока{ значение: снилс^ } },
|
||||
джесон.ДжесонКлючЗначение{ ключ: "паспорт", значение: джесон.ДжесонСтрока{ значение: паспорт^ } },
|
||||
джесон.ДжесонКлючЗначение{ ключ: "учитель", значение: джесон.ДжесонЧисло{ значение: учитель^.идентификатор } },
|
||||
джесон.ДжесонКлючЗначение{ ключ: "имя пользователя", значение: джесон.ДжесонСтрока{ значение: имя пользователя } }
|
||||
]
|
||||
})
|
||||
|
||||
вернуть хттп.создать ответ(
|
||||
хттп.ответ_201(),
|
||||
хттп.ХттпОтвет{ туловище: тело }
|
||||
)
|
||||
}
|
||||
|
||||
фн список учеников*(путь: Строка, параметры: массивы.Строки, обращение: маршрутизатор.Обращение): хттп.ХттпОтвет {
|
||||
пусть оплошность := ""
|
||||
пусть картотека = картотека.зайти()
|
||||
|
||||
пусть пользователь = репозитории.авторизовать по паспорту(бюрократия.получить данные паспорта(обращение), оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если пользователь = пусто {
|
||||
вернуть хттп.ответ_401()
|
||||
}
|
||||
|
||||
пусть учитель = репозитории.пользователь учитель(пользователь^.идентификатор, оплошность)
|
||||
пусть админ = репозитории.пользователь админ(пользователь^.идентификатор, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если учитель = пусто & ~админ {
|
||||
вернуть хттп.ответ_403()
|
||||
}
|
||||
|
||||
пусть фильтр по учителю := -1
|
||||
пусть параметр учитель = обращение.запрос-в-пути.найти("учитель")
|
||||
|
||||
если параметр учитель # пусто {
|
||||
пусть номер байта := 0
|
||||
строка.извлечь цел(параметр учитель^.значение, номер байта, фильтр по учителю)
|
||||
} иначе если ~админ {
|
||||
фильтр по учителю := учитель^.идентификатор
|
||||
}
|
||||
|
||||
если фильтр по учителю = -1 {
|
||||
вернуть хттп.ответ_400()
|
||||
}
|
||||
|
||||
пусть найдено = картотека.запросить безопасно(`
|
||||
SELECT s.id, s.snils, s.passport, s.mentor_id, u.first_name, u.last_name, u.middle_name, u.username
|
||||
FROM students s
|
||||
JOIN users u ON u.id = s.user_id
|
||||
WHERE s.mentor_id = ?
|
||||
ORDER BY s.id
|
||||
`, оплошность, фильтр по учителю)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
пусть джесон ученики = джесон.ДжесонМногоЗначений{}
|
||||
|
||||
цикл запись среди найдено.значения {
|
||||
пусть объект = запись(:джесон.ДжесонОбъект)
|
||||
|
||||
пусть идентификатор = объект.получить("id").число()
|
||||
пусть имя = объект.получить("first_name").строка()
|
||||
пусть фамилия = объект.получить("last_name").строка()
|
||||
пусть отчество = объект.получить("middle_name").строка()
|
||||
пусть снилс = объект.получить("snils").строка()
|
||||
пусть паспорт = объект.получить("passport").строка()
|
||||
пусть наставник = объект.получить("mentor_id").число()
|
||||
пусть имя пользователя = объект.получить("username").строка()
|
||||
|
||||
пусть студент = джесон.ДжесонОбъект{}
|
||||
студент.вставить("идентификатор", джесон.ДжесонЧисло{ значение: идентификатор^.значение })
|
||||
студент.вставить("имя", джесон.ДжесонСтрока{ значение: имя^ })
|
||||
студент.вставить("фамилия", джесон.ДжесонСтрока{ значение: фамилия^ })
|
||||
студент.вставить("отчество", джесон.ДжесонСтрока{ значение: отчество^ })
|
||||
студент.вставить("снилс", джесон.ДжесонСтрока{ значение: снилс^ })
|
||||
студент.вставить("паспорт", джесон.ДжесонСтрока{ значение: паспорт^ })
|
||||
студент.вставить("наставник", джесон.ДжесонЧисло{ значение: наставник^.значение })
|
||||
студент.вставить("имя пользователя", джесон.ДжесонСтрока{ значение: имя пользователя^ })
|
||||
|
||||
джесон ученики.значения.добавить(студент)
|
||||
}
|
||||
|
||||
пусть тело = джесон.сериализовать(джесон.ДжесонОбъект{
|
||||
значения: джесон.ДжесонКлючЗначения[
|
||||
джесон.ДжесонКлючЗначение{
|
||||
ключ: "ученики",
|
||||
значение: джесон ученики
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
вернуть хттп.ХттпОтвет{ туловище: тело }
|
||||
}
|
||||
|
||||
фн получить*(путь: Строка, параметры: массивы.Строки, обращение: маршрутизатор.Обращение): хттп.ХттпОтвет {
|
||||
пусть оплошность := ""
|
||||
пусть картотека = картотека.зайти()
|
||||
|
||||
пусть пользователь = репозитории.авторизовать по паспорту(бюрократия.получить данные паспорта(обращение), оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если пользователь = пусто {
|
||||
вернуть хттп.ответ_401()
|
||||
}
|
||||
|
||||
пусть учитель = репозитории.пользователь учитель(пользователь^.идентификатор, оплошность)
|
||||
пусть админ = репозитории.пользователь админ(пользователь^.идентификатор, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если учитель = пусто & ~админ {
|
||||
вернуть хттп.ответ_403()
|
||||
}
|
||||
|
||||
если длина(параметры) < 1 {
|
||||
вернуть хттп.ответ_400()
|
||||
}
|
||||
|
||||
пусть ид ученика = параметры[0]
|
||||
|
||||
пусть ученик := джесон.ДжесонМногоЗначений{}
|
||||
|
||||
если админ {
|
||||
ученик := картотека.запросить безопасно(`
|
||||
SELECT s.id, s.snils, s.passport, s.mentor_id, u.first_name, u.last_name, u.middle_name, u.username
|
||||
FROM students s
|
||||
JOIN users u ON u.id = s.user_id
|
||||
WHERE s.id = ?
|
||||
`, оплошность, ид ученика)
|
||||
} иначе {
|
||||
ученик := картотека.запросить безопасно(`
|
||||
SELECT s.id, s.snils, s.passport, s.mentor_id, u.first_name, u.last_name, u.middle_name, u.username
|
||||
FROM students s
|
||||
JOIN users u ON u.id = s.user_id
|
||||
WHERE s.id = ? AND s.mentor_id = ?
|
||||
`, оплошность, ид ученика, учитель^.идентификатор)
|
||||
}
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если длина(ученик.значения) = 0 {
|
||||
вернуть хттп.ответ_404()
|
||||
}
|
||||
|
||||
пусть объект = ученик.значения[0](:джесон.ДжесонОбъект)
|
||||
|
||||
пусть идентификатор = объект.получить("id").число()
|
||||
пусть имя = объект.получить("first_name").строка()
|
||||
пусть фамилия = объект.получить("last_name").строка()
|
||||
пусть отчество = объект.получить("middle_name").строка()
|
||||
пусть снилс = объект.получить("snils").строка()
|
||||
пусть паспорт = объект.получить("passport").строка()
|
||||
пусть наставник = объект.получить("mentor_id").число()
|
||||
пусть имя пользователя = объект.получить("username").строка()
|
||||
|
||||
если идентификатор = пусто | имя = пусто | фамилия = пусто | отчество = пусто | снилс = пусто | паспорт = пусто | наставник = пусто | имя пользователя = пусто {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
пусть тело = джесон.сериализовать(джесон.ДжесонОбъект{
|
||||
значения: джесон.ДжесонКлючЗначения[
|
||||
джесон.ДжесонКлючЗначение{ ключ: "идентификатор", значение: джесон.ДжесонЧисло{ значение: идентификатор^.значение } },
|
||||
джесон.ДжесонКлючЗначение{ ключ: "имя", значение: джесон.ДжесонСтрока{ значение: имя^ } },
|
||||
джесон.ДжесонКлючЗначение{ ключ: "фамилия", значение: джесон.ДжесонСтрока{ значение: фамилия^ } },
|
||||
джесон.ДжесонКлючЗначение{ ключ: "отчество", значение: джесон.ДжесонСтрока{ значение: отчество^ } },
|
||||
джесон.ДжесонКлючЗначение{ ключ: "снилс", значение: джесон.ДжесонСтрока{ значение: снилс^ } },
|
||||
джесон.ДжесонКлючЗначение{ ключ: "паспорт", значение: джесон.ДжесонСтрока{ значение: паспорт^ } },
|
||||
джесон.ДжесонКлючЗначение{ ключ: "наставник", значение: джесон.ДжесонЧисло{ значение: наставник^.значение } },
|
||||
джесон.ДжесонКлючЗначение{ ключ: "имя пользователя", значение: джесон.ДжесонСтрока{ значение: имя пользователя^ } }
|
||||
]
|
||||
})
|
||||
|
||||
вернуть хттп.ХттпОтвет{ туловище: тело }
|
||||
}
|
||||
|
||||
фн удалить*(путь: Строка, параметры: массивы.Строки, обращение: маршрутизатор.Обращение): хттп.ХттпОтвет {
|
||||
пусть оплошность := ""
|
||||
пусть картотека = картотека.зайти()
|
||||
|
||||
пусть пользователь = репозитории.авторизовать по паспорту(бюрократия.получить данные паспорта(обращение), оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если пользователь = пусто {
|
||||
вернуть хттп.ответ_401()
|
||||
}
|
||||
|
||||
пусть учитель = репозитории.пользователь учитель(пользователь^.идентификатор, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если учитель = пусто {
|
||||
вернуть хттп.ответ_403()
|
||||
}
|
||||
|
||||
если длина(параметры) < 1 {
|
||||
вернуть хттп.ответ_400()
|
||||
}
|
||||
|
||||
пусть ид ученика = параметры[0]
|
||||
|
||||
пусть удален = картотека.запросить безопасно(`
|
||||
DELETE FROM students WHERE id = ? AND mentor_id = ?
|
||||
RETURNING id, user_id
|
||||
`, оплошность, ид ученика, учитель^.идентификатор)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если длина(удален.значения) = 0 {
|
||||
вернуть хттп.ответ_404()
|
||||
}
|
||||
|
||||
пусть объект = удален.значения[0](:джесон.ДжесонОбъект)
|
||||
пусть айди пользователя = объект.получить("user_id").число()
|
||||
|
||||
если айди пользователя = пусто {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
картотека.запросить безопасно(`
|
||||
DELETE FROM users WHERE id = ?
|
||||
`, оплошность, айди пользователя^.значение)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
вернуть хттп.ответ_204()
|
||||
}
|
||||
|
||||
фн добавить маршруты*(маршрутизатор: маршрутизатор.Маршрутизатор): маршрутизатор.Маршрутизатор {
|
||||
маршрутизатор.добавить маршрут("/api/students", массивы.Строки["POST"], создать)
|
||||
маршрутизатор.добавить маршрут("/api/students", массивы.Строки["GET"], список учеников)
|
||||
маршрутизатор.добавить маршрут("/api/students/$", массивы.Строки["GET"], получить)
|
||||
маршрутизатор.добавить маршрут("/api/students/$", массивы.Строки["DELETE"], удалить)
|
||||
|
||||
вернуть маршрутизатор
|
||||
}
|
||||
215
исх/властелины/пользователи/учителя/учителя.tri
Normal file
215
исх/властелины/пользователи/учителя/учителя.tri
Normal file
@@ -0,0 +1,215 @@
|
||||
модуль учителя
|
||||
|
||||
импорт "стд::вывод"
|
||||
импорт "исх/строка"
|
||||
импорт "исх/спринтф"
|
||||
импорт "исх/массивы"
|
||||
импорт "исх/сеть/хттп"
|
||||
импорт "исх/форматы/джесон"
|
||||
импорт "исх/сеть/хттп/маршрутизатор"
|
||||
импорт "исх/картотека"
|
||||
импорт "исх/картотека/репозитории"
|
||||
импорт "исх/бюрократия"
|
||||
|
||||
фн создать*(путь: Строка, параметры: массивы.Строки, обращение: маршрутизатор.Обращение): хттп.ХттпОтвет {
|
||||
пусть картотека = картотека.зайти()
|
||||
пусть оплошность := ""
|
||||
пусть данные = джесон.парсить(обращение.туловище, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
пусть имя := данные.получить("имя").строка()
|
||||
пусть фамилия := данные.получить("фамилия").строка()
|
||||
пусть отчество := данные.получить("отчество").строка()
|
||||
пусть образование := данные.получить("образование").строка()
|
||||
пусть пароль := данные.получить("пароль").строка()
|
||||
пусть повтор пароля := данные.получить("повтор пароля").строка()
|
||||
пусть аватар = данные.получить("аватар").строка()
|
||||
пусть аватар урл := ""
|
||||
|
||||
если имя = пусто | фамилия = пусто | отчество = пусто | образование = пусто | пароль = пусто | повтор пароля = пусто {
|
||||
вернуть хттп.ответ_400()
|
||||
}
|
||||
|
||||
если имя^ = "" | фамилия^ = "" | отчество^ = "" | образование^ = "" | пароль^ = "" | повтор пароля^ = "" {
|
||||
вернуть хттп.ответ_400()
|
||||
}
|
||||
|
||||
если пароль^ # повтор пароля^ {
|
||||
вернуть хттп.создать ответ(
|
||||
хттп.ответ_400(),
|
||||
хттп.ХттпОтвет{
|
||||
туловище: "Пароли не совпадают.",
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
пусть имя пользователя = спринтф.ф("$стр.$стр", имя^, фамилия^)
|
||||
|
||||
пусть ответ = картотека.запросить безопасно(`
|
||||
INSERT INTO users (first_name, last_name, middle_name, username, password)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
RETURNING id
|
||||
`, оплошность, имя^, фамилия^, отчество^, имя пользователя, пароль^)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
пусть айди пользователя = ответ.значения[0](:джесон.ДжесонОбъект).получить("id").число()
|
||||
|
||||
если айди пользователя = пусто {
|
||||
авария("неверный ответ от базы данных")
|
||||
}
|
||||
|
||||
если аватар # пусто & аватар^ # "" {
|
||||
пусть урл = хттп.парсить урл(аватар^, оплошность)
|
||||
|
||||
если оплошность = "" {
|
||||
пусть ответ = хттп.послать на три буквы(урл.хост, урл.порт, урл.путь)
|
||||
пусть размер контента := 0
|
||||
|
||||
цикл [номер]заглавие среди ответ.заглавия {
|
||||
если заглавие.имя = "Content-Length" {
|
||||
пусть № байта := 0
|
||||
строка.извлечь цел(заглавие.значение, № байта, размер контента)
|
||||
прервать
|
||||
}
|
||||
}
|
||||
|
||||
если размер контента > 0 & размер контента < 1000000 {
|
||||
аватар урл := аватар^
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
пусть учитель = картотека.запросить безопасно(`
|
||||
INSERT INTO teachers (user_id, education, avatar_url)
|
||||
VALUES (?, ?, ?)
|
||||
RETURNING id
|
||||
`, оплошность, айди пользователя^.значение, образование^, аватар урл)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если длина(учитель.значения) = 0 {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
пусть созданный учитель = учитель.значения[0](:джесон.ДжесонОбъект)
|
||||
пусть идентификатор учителя = созданный учитель.получить("id").число()
|
||||
|
||||
если идентификатор учителя = пусто {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
пусть тело = джесон.сериализовать(джесон.ДжесонОбъект{
|
||||
значения: джесон.ДжесонКлючЗначения[
|
||||
джесон.ДжесонКлючЗначение{ ключ: "идентификатор", значение: джесон.ДжесонЧисло{ значение: идентификатор учителя^.значение } },
|
||||
джесон.ДжесонКлючЗначение{ ключ: "образование", значение: джесон.ДжесонСтрока{ значение: образование^ } },
|
||||
джесон.ДжесонКлючЗначение{ ключ: "имя", значение: джесон.ДжесонСтрока{ значение: имя^ } },
|
||||
джесон.ДжесонКлючЗначение{ ключ: "фамилия", значение: джесон.ДжесонСтрока{ значение: фамилия^ } },
|
||||
джесон.ДжесонКлючЗначение{ ключ: "отчество", значение: джесон.ДжесонСтрока{ значение: отчество^ } },
|
||||
джесон.ДжесонКлючЗначение{ ключ: "имя пользователя", значение: джесон.ДжесонСтрока{ значение: имя пользователя } }
|
||||
]
|
||||
})
|
||||
|
||||
вернуть хттп.создать ответ(
|
||||
хттп.ответ_201(),
|
||||
хттп.ХттпОтвет{ туловище: тело }
|
||||
)
|
||||
}
|
||||
|
||||
фн список*(путь: Строка, параметры: массивы.Строки, обращение: маршрутизатор.Обращение): хттп.ХттпОтвет {
|
||||
пусть оплошность := ""
|
||||
пусть картотека = картотека.зайти()
|
||||
|
||||
пусть пользователь = репозитории.авторизовать по паспорту(бюрократия.получить данные паспорта(обращение), оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если пользователь = пусто {
|
||||
вернуть хттп.ответ_401()
|
||||
}
|
||||
|
||||
пусть админ = репозитории.пользователь админ(пользователь^.идентификатор, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если ~админ {
|
||||
вернуть хттп.ответ_403()
|
||||
}
|
||||
|
||||
пусть размер страницы := 20
|
||||
пусть номер страницы := 1
|
||||
|
||||
пусть параметр страница = обращение.запрос-в-пути.найти("страница")
|
||||
если параметр страница # пусто {
|
||||
пусть номер байта := 0
|
||||
строка.извлечь цел(параметр страница^.значение, номер байта, номер страницы)
|
||||
}
|
||||
|
||||
если номер страницы < 1 {
|
||||
вернуть хттп.ответ_400()
|
||||
}
|
||||
|
||||
пусть смещение := (номер страницы - 1) * размер страницы
|
||||
|
||||
пусть учителя = картотека.запросить безопасно(`
|
||||
SELECT t.id, t.user_id, t.education, t.avatar_url,
|
||||
u.first_name, u.last_name, u.middle_name, u.username
|
||||
FROM teachers t
|
||||
JOIN users u ON u.id = t.user_id
|
||||
ORDER BY t.id
|
||||
LIMIT ? OFFSET ?
|
||||
`, оплошность, размер страницы, смещение)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
пусть джесон учителя = джесон.ДжесонМногоЗначений{}
|
||||
|
||||
цикл [номер]запись среди учителя.значения {
|
||||
пусть объект = запись(:джесон.ДжесонОбъект)
|
||||
|
||||
пусть идентификатор = объект.получить("id").число()
|
||||
пусть образование = объект.получить("education").строка()
|
||||
пусть имя = объект.получить("first_name").строка()
|
||||
пусть фамилия = объект.получить("last_name").строка()
|
||||
пусть отчество = объект.получить("middle_name").строка()
|
||||
пусть имя пользователя = объект.получить("username").строка()
|
||||
|
||||
пусть учитель = джесон.ДжесонОбъект{}
|
||||
если идентификатор # пусто { учитель.вставить("идентификатор", джесон.ДжесонЧисло{ значение: идентификатор^.значение }) }
|
||||
если образование # пусто { учитель.вставить("образование", джесон.ДжесонСтрока{ значение: образование^ }) }
|
||||
если имя # пусто { учитель.вставить("имя", джесон.ДжесонСтрока{ значение: имя^ }) }
|
||||
если фамилия # пусто { учитель.вставить("фамилия", джесон.ДжесонСтрока{ значение: фамилия^ }) }
|
||||
если отчество # пусто { учитель.вставить("отчество", джесон.ДжесонСтрока{ значение: отчество^ }) }
|
||||
если имя пользователя # пусто { учитель.вставить("имя пользователя", джесон.ДжесонСтрока{ значение: имя пользователя^ }) }
|
||||
|
||||
джесон учителя.значения.добавить(учитель)
|
||||
}
|
||||
|
||||
пусть туловище = джесон.сериализовать(джесон.ДжесонОбъект{
|
||||
значения: джесон.ДжесонКлючЗначения[
|
||||
джесон.ДжесонКлючЗначение{ ключ: "учителя", значение: джесон учителя }
|
||||
]
|
||||
})
|
||||
|
||||
вернуть хттп.ХттпОтвет{ туловище: туловище }
|
||||
}
|
||||
|
||||
фн добавить маршруты*(маршрутизатор: маршрутизатор.Маршрутизатор): маршрутизатор.Маршрутизатор {
|
||||
маршрутизатор.добавить маршрут("/api/users", массивы.Строки["POST"], создать)
|
||||
маршрутизатор.добавить маршрут("/api/teachers", массивы.Строки["GET"], список)
|
||||
|
||||
вернуть маршрутизатор
|
||||
}
|
||||
392
исх/властелины/уроки/уроки.tri
Normal file
392
исх/властелины/уроки/уроки.tri
Normal file
@@ -0,0 +1,392 @@
|
||||
модуль уроки
|
||||
|
||||
импорт "стд::вывод"
|
||||
импорт "исх/строка"
|
||||
импорт "исх/спринтф"
|
||||
импорт "исх/массивы"
|
||||
импорт "исх/сеть/хттп"
|
||||
импорт "исх/форматы/джесон"
|
||||
импорт "исх/сеть/хттп/маршрутизатор"
|
||||
импорт "исх/картотека"
|
||||
импорт "исх/картотека/репозитории"
|
||||
импорт "исх/бюрократия"
|
||||
|
||||
фн добавить урок*(путь: Строка, параметры: массивы.Строки, обращение: маршрутизатор.Обращение): хттп.ХттпОтвет {
|
||||
пусть оплошность := ""
|
||||
пусть картотека = картотека.зайти()
|
||||
|
||||
пусть пользователь = репозитории.авторизовать по паспорту(бюрократия.получить данные паспорта(обращение), оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если пользователь = пусто {
|
||||
вернуть хттп.ответ_401()
|
||||
}
|
||||
|
||||
пусть учитель = репозитории.пользователь учитель(пользователь^.идентификатор, оплошность)
|
||||
пусть админ = репозитории.пользователь админ(пользователь^.идентификатор, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если учитель = пусто & ~админ {
|
||||
вернуть хттп.ответ_403()
|
||||
}
|
||||
|
||||
если длина(параметры) < 1 {
|
||||
вернуть хттп.ответ_400()
|
||||
}
|
||||
|
||||
пусть ид класса = параметры[0]
|
||||
|
||||
пусть клass := джесон.ДжесонМногоЗначений{}
|
||||
|
||||
если админ {
|
||||
клass := картотека.запросить безопасно(`
|
||||
SELECT id FROM classes WHERE id = ?
|
||||
`, оплошность, ид класса)
|
||||
} иначе {
|
||||
клass := картотека.запросить безопасно(`
|
||||
SELECT id FROM classes WHERE id = ? AND creator_teacher_id = ?
|
||||
`, оплошность, ид класса, учитель^.идентификатор)
|
||||
}
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если длина(клass.значения) = 0 {
|
||||
вернуть хттп.ответ_403()
|
||||
}
|
||||
|
||||
пусть данные = джесон.парсить(обращение.туловище, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_400()
|
||||
}
|
||||
|
||||
пусть дата := данные.получить("дата").строка()
|
||||
пусть название := данные.получить("название").строка()
|
||||
пусть домашка := данные.получить("домашнее задание").строка()
|
||||
|
||||
пусть строка даты := ""
|
||||
|
||||
если дата # пусто {
|
||||
строка даты := дата^
|
||||
} иначе {
|
||||
пусть дата урока поле := данные.получить("дата урока").строка()
|
||||
|
||||
если дата урока поле # пусто {
|
||||
строка даты := дата урока поле^
|
||||
}
|
||||
}
|
||||
|
||||
пусть строка названия := ""
|
||||
|
||||
если название # пусто {
|
||||
строка названия := название^
|
||||
} иначе {
|
||||
пусть тема := данные.получить("тема").строка()
|
||||
|
||||
если тема # пусто {
|
||||
строка названия := тема^
|
||||
}
|
||||
}
|
||||
|
||||
если строка даты = "" | строка названия = "" {
|
||||
вернуть хттп.ответ_400()
|
||||
}
|
||||
|
||||
пусть текст домашки := ""
|
||||
|
||||
если домашка # пусто {
|
||||
текст домашки := домашка^
|
||||
} иначе {
|
||||
пусть поле домашка = данные.получить("домашка").строка()
|
||||
|
||||
если поле домашка # пусто {
|
||||
текст домашки := поле домашка^
|
||||
}
|
||||
}
|
||||
|
||||
пусть ответ = картотека.запросить безопасно(`
|
||||
INSERT INTO lessons (class_id, date, title, homework)
|
||||
VALUES (?, ?, ?, ?)
|
||||
RETURNING id, class_id, date, title, homework
|
||||
`, оплошность, ид класса, строка даты, строка названия, текст домашки)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_422()
|
||||
}
|
||||
|
||||
если длина(ответ.значения) = 0 {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
пусть созданный = ответ.значения[0](:джесон.ДжесонОбъект)
|
||||
пусть идентификатор урока = созданный.получить("id").число()^.значение
|
||||
пусть идентификатор класса = созданный.получить("class_id").число()^.значение
|
||||
пусть дата урока = созданный.получить("date").строка()^
|
||||
пусть название урока = созданный.получить("title").строка()^
|
||||
пусть поле домашки = созданный.получить("homework").строка()
|
||||
|
||||
пусть значение домашки := ""
|
||||
|
||||
если поле домашки # пусто {
|
||||
значение домашки := поле домашки^
|
||||
}
|
||||
|
||||
пусть туловище = джесон.сериализовать(джесон.ДжесонОбъект{
|
||||
значения: джесон.ДжесонКлючЗначения[
|
||||
джесон.ДжесонКлючЗначение{ключ: "идентификатор", значение: джесон.ДжесонЧисло{значение: идентификатор урока}},
|
||||
джесон.ДжесонКлючЗначение{ключ: "идентификатор класса", значение: джесон.ДжесонЧисло{значение: идентификатор класса}},
|
||||
джесон.ДжесонКлючЗначение{ключ: "дата", значение: джесон.ДжесонСтрока{значение: дата урока}},
|
||||
джесон.ДжесонКлючЗначение{ключ: "название", значение: джесон.ДжесонСтрока{значение: название урока}},
|
||||
джесон.ДжесонКлючЗначение{ключ: "домашнее задание", значение: джесон.ДжесонСтрока{значение: значение домашки}}
|
||||
]
|
||||
})
|
||||
|
||||
вернуть хттп.создать ответ(
|
||||
хттп.ответ_201(),
|
||||
хттп.ХттпОтвет{туловище: туловище}
|
||||
)
|
||||
}
|
||||
|
||||
фн список уроков*(путь: Строка, параметры: массивы.Строки, обращение: маршрутизатор.Обращение): хттп.ХттпОтвет {
|
||||
пусть оплошность := ""
|
||||
пусть картотека = картотека.зайти()
|
||||
|
||||
если длина(параметры) < 1 {
|
||||
вернуть хттп.ответ_400()
|
||||
}
|
||||
|
||||
пусть ид класса = параметры[0]
|
||||
пусть фильтр дата := ""
|
||||
пусть есть фильтр := ложь
|
||||
|
||||
если длина(параметры) > 1 {
|
||||
фильтр дата := параметры[1]
|
||||
есть фильтр := истина
|
||||
}
|
||||
|
||||
пусть пользователь = репозитории.авторизовать по паспорту(бюрократия.получить данные паспорта(обращение), оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если пользователь = пусто {
|
||||
вернуть хттп.ответ_401()
|
||||
}
|
||||
|
||||
пусть учитель = репозитории.пользователь учитель(пользователь^.идентификатор, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
пусть ученик = репозитории.пользователь ученик(пользователь^.идентификатор, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
пусть админ = репозитории.пользователь админ(пользователь^.идентификатор, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
пусть данные класса = картотека.запросить безопасно(`
|
||||
SELECT id, creator_teacher_id FROM classes WHERE id = ?
|
||||
`, оплошность, ид класса)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если длина(данные класса.значения) = 0 {
|
||||
вернуть хттп.ответ_404()
|
||||
}
|
||||
|
||||
пусть объект класса = данные класса.значения[0](:джесон.ДжесонОбъект)
|
||||
пусть поле создателя = объект класса.получить("creator_teacher_id").число()
|
||||
пусть идентификатор создателя: Цел64 := -1
|
||||
пусть есть создатель := ложь
|
||||
|
||||
если поле создателя # пусто {
|
||||
идентификатор создателя := поле создателя^.значение
|
||||
есть создатель := истина
|
||||
}
|
||||
|
||||
пусть учитель имеет доступ := ложь
|
||||
|
||||
если админ {
|
||||
учитель имеет доступ := истина
|
||||
}
|
||||
|
||||
если учитель # пусто {
|
||||
если есть создатель {
|
||||
если учитель^.идентификатор = идентификатор создателя {
|
||||
учитель имеет доступ := истина
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
если ~ учитель имеет доступ {
|
||||
если ученик = пусто {
|
||||
вернуть хттп.ответ_403()
|
||||
}
|
||||
|
||||
пусть проверка ученика = картотека.запросить безопасно(`
|
||||
SELECT id FROM class_students WHERE class_id = ? AND student_id = ?
|
||||
`, оплошность, ид класса, ученик^.идентификатор)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если длина(проверка ученика.значения) = 0 {
|
||||
вернуть хттп.ответ_403()
|
||||
}
|
||||
}
|
||||
|
||||
пусть уроки ответ: джесон.ДжесонМногоЗначений := джесон.ДжесонМногоЗначений{}
|
||||
|
||||
если есть фильтр {
|
||||
уроки ответ := картотека.запросить безопасно(`
|
||||
SELECT id, class_id, date, title, homework
|
||||
FROM lessons
|
||||
WHERE class_id = ? AND date = ?
|
||||
ORDER BY date, id
|
||||
`, оплошность, ид класса, фильтр дата)
|
||||
} иначе {
|
||||
уроки ответ := картотека.запросить безопасно(`
|
||||
SELECT id, class_id, date, title, homework
|
||||
FROM lessons
|
||||
WHERE class_id = ?
|
||||
ORDER BY date, id
|
||||
`, оплошность, ид класса)
|
||||
}
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
пусть джесон уроки = джесон.ДжесонМногоЗначений{}
|
||||
|
||||
цикл [номер]запись среди уроки ответ.значения {
|
||||
пусть объект = запись(:джесон.ДжесонОбъект)
|
||||
пусть идентификатор = объект.получить("id").число()^.значение
|
||||
пусть ид класса урока = объект.получить("class_id").число()^.значение
|
||||
пусть дата урока = объект.получить("date").строка()^
|
||||
пусть название урока = объект.получить("title").строка()^
|
||||
пусть поле домашки = объект.получить("homework").строка()
|
||||
пусть значение домашки := ""
|
||||
|
||||
если поле домашки # пусто {
|
||||
значение домашки := поле домашки^
|
||||
}
|
||||
|
||||
пусть урок = джесон.ДжесонОбъект{}
|
||||
урок.вставить("идентификатор", джесон.ДжесонЧисло{значение: идентификатор})
|
||||
урок.вставить("идентификатор класса", джесон.ДжесонЧисло{значение: ид класса урока})
|
||||
урок.вставить("дата", джесон.ДжесонСтрока{значение: дата урока})
|
||||
урок.вставить("название", джесон.ДжесонСтрока{значение: название урока})
|
||||
урок.вставить("домашнее задание", джесон.ДжесонСтрока{значение: значение домашки})
|
||||
|
||||
джесон уроки.значения.добавить(урок)
|
||||
}
|
||||
|
||||
пусть тело = джесон.сериализовать(джесон.ДжесонОбъект{
|
||||
значения: джесон.ДжесонКлючЗначения[
|
||||
джесон.ДжесонКлючЗначение{
|
||||
ключ: "уроки",
|
||||
значение: джесон уроки
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
вернуть хттп.ХттпОтвет{туловище: тело}
|
||||
}
|
||||
|
||||
фн удалить урок*(путь: Строка, параметры: массивы.Строки, обращение: маршрутизатор.Обращение): хттп.ХттпОтвет {
|
||||
пусть оплошность := ""
|
||||
пусть картотека = картотека.зайти()
|
||||
|
||||
пусть пользователь = репозитории.авторизовать по паспорту(бюрократия.получить данные паспорта(обращение), оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если пользователь = пусто {
|
||||
вернуть хттп.ответ_401()
|
||||
}
|
||||
|
||||
пусть учитель = репозитории.пользователь учитель(пользователь^.идентификатор, оплошность)
|
||||
пусть админ = репозитории.пользователь админ(пользователь^.идентификатор, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если учитель = пусто & ~админ {
|
||||
вернуть хттп.ответ_403()
|
||||
}
|
||||
|
||||
если длина(параметры) < 2 {
|
||||
вернуть хттп.ответ_400()
|
||||
}
|
||||
|
||||
пусть ид класса = параметры[0]
|
||||
пусть ид урока = параметры[1]
|
||||
|
||||
пусть клass := джесон.ДжесонМногоЗначений{}
|
||||
|
||||
если админ {
|
||||
клass := картотека.запросить безопасно(`
|
||||
SELECT id FROM classes WHERE id = ?
|
||||
`, оплошность, ид класса)
|
||||
} иначе {
|
||||
клass := картотека.запросить безопасно(`
|
||||
SELECT id FROM classes WHERE id = ? AND creator_teacher_id = ?
|
||||
`, оплошность, ид класса, учитель^.идентификатор)
|
||||
}
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если длина(клass.значения) = 0 {
|
||||
вернуть хттп.ответ_403()
|
||||
}
|
||||
|
||||
пусть ответ = картотека.запросить безопасно(`
|
||||
DELETE FROM lessons WHERE id = ? AND class_id = ?
|
||||
RETURNING id
|
||||
`, оплошность, ид урока, ид класса)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть хттп.ответ_500()
|
||||
}
|
||||
|
||||
если длина(ответ.значения) = 0 {
|
||||
вернуть хттп.ответ_404()
|
||||
}
|
||||
|
||||
вернуть хттп.ответ_204()
|
||||
}
|
||||
|
||||
фн добавить маршруты*(маршрутизатор: маршрутизатор.Маршрутизатор): маршрутизатор.Маршрутизатор {
|
||||
маршрутизатор.добавить маршрут("/api/classes/$/lessons", массивы.Строки["POST"], добавить урок)
|
||||
маршрутизатор.добавить маршрут("/api/classes/$/lessons", массивы.Строки["GET"], список уроков)
|
||||
маршрутизатор.добавить маршрут("/api/classes/$/lessons/$", массивы.Строки["GET"], список уроков)
|
||||
маршрутизатор.добавить маршрут("/api/classes/$/lessons/date/$", массивы.Строки["GET"], список уроков)
|
||||
маршрутизатор.добавить маршрут("/api/classes/$/lessons/$", массивы.Строки["DELETE"], удалить урок)
|
||||
|
||||
вернуть маршрутизатор
|
||||
}
|
||||
5
исх/вперед-назад/типы.tri
Normal file
5
исх/вперед-назад/типы.tri
Normal file
@@ -0,0 +1,5 @@
|
||||
модуль вперед-назад
|
||||
|
||||
тип Крипипаста* = протокол {
|
||||
фн прочитать(сколько: Цел64): Строка
|
||||
}
|
||||
13
исх/картотека/картотека.tri
Normal file
13
исх/картотека/картотека.tri
Normal file
@@ -0,0 +1,13 @@
|
||||
модуль картотека
|
||||
|
||||
импорт "исх/бд/скуля"
|
||||
|
||||
пусть картотека: скуля.Картотека := скуля.Картотека{}
|
||||
|
||||
фн зайти*(): скуля.Картотека {
|
||||
вернуть картотека
|
||||
}
|
||||
|
||||
вход {
|
||||
картотека := скуля.открыть картотеку("var/srab.db")
|
||||
}
|
||||
130
исх/картотека/репозитории/пользователь.tri
Normal file
130
исх/картотека/репозитории/пользователь.tri
Normal file
@@ -0,0 +1,130 @@
|
||||
модуль репозитории
|
||||
|
||||
импорт "исх/бд/скуля"
|
||||
импорт "исх/картотека"
|
||||
импорт "исх/форматы/джесон"
|
||||
импорт "исх/бюрократия"
|
||||
|
||||
тип Пользователь = класс {
|
||||
идентификатор*: Цел64 := 0
|
||||
имя*: Строка := ""
|
||||
фамилия*: Строка := ""
|
||||
отчество*: Строка := ""
|
||||
имя пользователя*: Строка := ""
|
||||
пароль*: Строка := ""
|
||||
}
|
||||
|
||||
тип Учитель = класс {
|
||||
идентификатор*: Цел64 := 0
|
||||
идентификатор пользователя*: Цел64 := 0
|
||||
образование*: Строка := ""
|
||||
урурурл аватара*: Строка := ""
|
||||
}
|
||||
|
||||
тип Ученик = класс {
|
||||
идентификатор*: Цел64 := 0
|
||||
идентификатор пользователя*: Цел64 := 0
|
||||
идентификатор ментора*: Цел64 := 0
|
||||
снилс*: Строка := ""
|
||||
паспорт*: Строка := ""
|
||||
}
|
||||
|
||||
фн авторизовать пользователя*(имя пользователя: Строка, пароль: Строка, оплошность := Строка): мб Пользователь {
|
||||
пусть картотека = картотека.зайти()
|
||||
пусть ответ = картотека.запросить безопасно(`
|
||||
SELECT id, first_name, last_name, middle_name FROM users WHERE username = ? AND password = ?
|
||||
`, оплошность, имя пользователя, пароль)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть Пользователь{}
|
||||
}
|
||||
|
||||
если длина(ответ.значения) = 0 {
|
||||
вернуть пусто
|
||||
}
|
||||
|
||||
пусть объект = ответ.значения[0](:джесон.ДжесонОбъект)
|
||||
|
||||
вернуть Пользователь{
|
||||
идентификатор: объект.получить("id").число()^.значение,
|
||||
имя: объект.получить("first_name").строка()^,
|
||||
фамилия: объект.получить("last_name").строка()^,
|
||||
отчество: объект.получить("middle_name").строка()^,
|
||||
имя пользователя: имя пользователя,
|
||||
пароль: пароль
|
||||
}
|
||||
}
|
||||
|
||||
фн авторизовать по паспорту*(паспорт: мб бюрократия.Паспорт, оплошность := Строка): мб Пользователь {
|
||||
если паспорт = пусто {
|
||||
вернуть пусто
|
||||
}
|
||||
|
||||
вернуть авторизовать пользователя(паспорт^.имя пользователя, паспорт^.пароль, оплошность)
|
||||
}
|
||||
|
||||
фн пользователь учитель*(ид: Цел64, оплошность := Строка): мб Учитель {
|
||||
пусть картотека = картотека.зайти()
|
||||
пусть ответ = картотека.запросить безопасно(`
|
||||
SELECT user_id, education, avatar_url, id FROM teachers WHERE user_id = ?
|
||||
`, оплошность, ид)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть пусто
|
||||
}
|
||||
|
||||
если длина(ответ.значения) = 0 {
|
||||
вернуть пусто
|
||||
}
|
||||
|
||||
пусть объект = ответ.значения[0](:джесон.ДжесонОбъект)
|
||||
|
||||
вернуть Учитель{
|
||||
идентификатор: объект.получить("id").число()^.значение,
|
||||
идентификатор пользователя: ид,
|
||||
образование: объект.получить("education").строка()^,
|
||||
урурурл аватара: объект.получить("avatar_url").строка()^
|
||||
}
|
||||
}
|
||||
|
||||
фн пользователь ученик*(ид: Цел64, оплошность := Строка): мб Ученик {
|
||||
пусть картотека = картотека.зайти()
|
||||
пусть ответ = картотека.запросить безопасно(`
|
||||
SELECT * FROM students WHERE user_id = ?
|
||||
`, оплошность, ид)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть пусто
|
||||
}
|
||||
|
||||
если длина(ответ.значения) = 0 {
|
||||
вернуть пусто
|
||||
}
|
||||
|
||||
пусть объект = ответ.значения[0](:джесон.ДжесонОбъект)
|
||||
|
||||
вернуть Ученик{
|
||||
идентификатор: объект.получить("id").число()^.значение,
|
||||
идентификатор пользователя: ид,
|
||||
идентификатор ментора: объект.получить("mentor_id").число()^.значение,
|
||||
снилс: объект.получить("snils").строка()^,
|
||||
паспорт: объект.получить("passport").строка()^
|
||||
}
|
||||
}
|
||||
|
||||
фн пользователь админ*(ид: Цел64, оплошность := Строка): Лог {
|
||||
пусть картотека = картотека.зайти()
|
||||
пусть учитель = пользователь учитель(ид, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть ложь
|
||||
}
|
||||
|
||||
пусть ученик = пользователь ученик(ид, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
вернуть ложь
|
||||
}
|
||||
|
||||
вернуть учитель = пусто & ученик = пусто
|
||||
}
|
||||
24
исх/маршруты/маршруты.tri
Normal file
24
исх/маршруты/маршруты.tri
Normal file
@@ -0,0 +1,24 @@
|
||||
модуль маршруты
|
||||
|
||||
импорт "исх/массивы"
|
||||
импорт "исх/сеть/хттп/маршрутизатор"
|
||||
|
||||
импорт "исх/властелины/главный"
|
||||
импорт "исх/властелины/классы"
|
||||
импорт "исх/властелины/уроки"
|
||||
импорт "исх/властелины/пользователи"
|
||||
импорт "исх/властелины/пользователи/ученики"
|
||||
импорт "исх/властелины/пользователи/учителя"
|
||||
|
||||
фн получить маршрутизатор*(): маршрутизатор.Маршрутизатор {
|
||||
пусть маршрутизатор = маршрутизатор.Маршрутизатор{}
|
||||
|
||||
главный.добавить маршруты(маршрутизатор)
|
||||
пользователи.добавить маршруты(маршрутизатор)
|
||||
ученики.добавить маршруты(маршрутизатор)
|
||||
учителя.добавить маршруты(маршрутизатор)
|
||||
классы.добавить маршруты(маршрутизатор)
|
||||
уроки.добавить маршруты(маршрутизатор)
|
||||
|
||||
вернуть маршрутизатор
|
||||
}
|
||||
3
исх/массивы/массивы.tri
Normal file
3
исх/массивы/массивы.tri
Normal file
@@ -0,0 +1,3 @@
|
||||
модуль массивы
|
||||
|
||||
тип Строки* = []Строка
|
||||
112
исх/миграции/миграции.tri
Normal file
112
исх/миграции/миграции.tri
Normal file
@@ -0,0 +1,112 @@
|
||||
модуль миграции
|
||||
|
||||
импорт "исх/бд/скуля"
|
||||
|
||||
фн мигрировать*(картотека: скуля.Картотека) {
|
||||
пусть оплошность := ""
|
||||
|
||||
картотека.выполнить(`PRAGMA foreign_keys = ON;`, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
авария(оплошность)
|
||||
}
|
||||
|
||||
картотека.выполнить(`
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
first_name TEXT NOT NULL,
|
||||
last_name TEXT NOT NULL,
|
||||
middle_name TEXT NOT NULL,
|
||||
username TEXT NOT NULL UNIQUE,
|
||||
password TEXT NOT NULL
|
||||
);`, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
авария(оплошность)
|
||||
}
|
||||
|
||||
картотека.выполнить(`
|
||||
CREATE TABLE IF NOT EXISTS teachers (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL UNIQUE,
|
||||
education TEXT,
|
||||
avatar_url TEXT,
|
||||
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
);`, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
авария(оплошность)
|
||||
}
|
||||
|
||||
картотека.выполнить(`
|
||||
CREATE TABLE IF NOT EXISTS students (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL UNIQUE,
|
||||
mentor_id INTEGER, -- "чей ученик" — id учителя (может быть NULL)
|
||||
snils TEXT,
|
||||
passport TEXT,
|
||||
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY(mentor_id) REFERENCES teachers(id) ON DELETE SET NULL
|
||||
);`, оплошность)
|
||||
|
||||
картотека.выполнить(`
|
||||
CREATE TABLE IF NOT EXISTS classes (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
number INTEGER NOT NULL,
|
||||
letter TEXT NOT NULL,
|
||||
creator_teacher_id INTEGER,
|
||||
FOREIGN KEY(creator_teacher_id) REFERENCES teachers(id) ON DELETE SET NULL
|
||||
);`, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
авария(оплошность)
|
||||
}
|
||||
|
||||
картотека.выполнить(`
|
||||
CREATE TABLE IF NOT EXISTS class_students (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
class_id INTEGER NOT NULL,
|
||||
student_id INTEGER NOT NULL,
|
||||
UNIQUE(class_id, student_id),
|
||||
FOREIGN KEY(class_id) REFERENCES classes(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY(student_id) REFERENCES students(id) ON DELETE CASCADE
|
||||
);`, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
авария(оплошность)
|
||||
}
|
||||
|
||||
картотека.выполнить(`
|
||||
CREATE TABLE IF NOT EXISTS lessons (
|
||||
id INTEGER PRIMARY
|
||||
KEY AUTOINCREMENT,
|
||||
class_id INTEGER NOT NULL,
|
||||
date DATE NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
homework TEXT,
|
||||
FOREIGN KEY(class_id) REFERENCES classes(id) ON DELETE CASCADE
|
||||
);`, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
авария(оплошность)
|
||||
}
|
||||
|
||||
картотека.выполнить(`
|
||||
INSERT OR IGNORE INTO users (
|
||||
first_name,
|
||||
last_name,
|
||||
middle_name,
|
||||
username,
|
||||
password
|
||||
) VALUES (
|
||||
'Админ',
|
||||
'Админович',
|
||||
'',
|
||||
'admin',
|
||||
'correct horse battery staple'
|
||||
);`, оплошность)
|
||||
|
||||
если оплошность # "" {
|
||||
авария(оплошность)
|
||||
}
|
||||
}
|
||||
9
исх/отдых/отдых.tri
Normal file
9
исх/отдых/отдых.tri
Normal file
@@ -0,0 +1,9 @@
|
||||
модуль отдых
|
||||
|
||||
// c:include <unistd.h>
|
||||
|
||||
фн sleep(секунды: Цел64) @внеш
|
||||
|
||||
фн отдохнуть*(секунды: Цел64) {
|
||||
sleep(секунды)
|
||||
}
|
||||
7
исх/сборщик-мусора/сборщик-мусора.tri
Normal file
7
исх/сборщик-мусора/сборщик-мусора.tri
Normal file
@@ -0,0 +1,7 @@
|
||||
модуль сборщик-мусора
|
||||
|
||||
импорт "стд::платформа"
|
||||
|
||||
фн собрать*() {
|
||||
платформа.завершить программу(0)
|
||||
}
|
||||
57
исх/сеть/тцп/сервер.tri
Normal file
57
исх/сеть/тцп/сервер.tri
Normal file
@@ -0,0 +1,57 @@
|
||||
модуль тцп
|
||||
|
||||
// c:include "suckit.h"
|
||||
|
||||
фн create_socket_fd(port: Цел64): Цел64 @внеш
|
||||
фн accept_socket(fd: Цел64): Цел64 @внеш
|
||||
фн read_to_string(fd: Цел64, bytes: Цел64): Строка @внеш
|
||||
фн close_socket(socket: Цел64) @внеш
|
||||
фн write_string(socket: Цел64, data: Строка) @внеш
|
||||
фн connect_socket(host: Строка, port: Цел64): Цел64 @внеш
|
||||
|
||||
тип ТцпСервер* = класс {
|
||||
фд: Цел64 = 0
|
||||
}
|
||||
|
||||
тип ТцпСоединение* = класс {
|
||||
фд: Цел64 = 0
|
||||
}
|
||||
|
||||
фн создать сервер*(порт: Цел64): ТцпСервер {
|
||||
пусть фд = create_socket_fd(порт)
|
||||
|
||||
вернуть ТцпСервер{
|
||||
фд: фд
|
||||
}
|
||||
}
|
||||
|
||||
фн (с: ТцпСервер) принять чертово соединение*(): ТцпСоединение {
|
||||
пусть фд = accept_socket(с.фд)
|
||||
|
||||
вернуть ТцпСоединение{
|
||||
фд: фд
|
||||
}
|
||||
}
|
||||
|
||||
фн (с: ТцпСоединение) прочитать*(сколько: Цел64): Строка {
|
||||
вернуть read_to_string(с.фд, сколько)
|
||||
}
|
||||
|
||||
фн (с: ТцпСоединение) записать*(данные: Строка) {
|
||||
write_string(с.фд, данные)
|
||||
}
|
||||
|
||||
фн (с: ТцпСоединение) закрыть*() {
|
||||
close_socket(с.фд)
|
||||
}
|
||||
|
||||
фн (с: ТцпСервер) закрыть*() {
|
||||
close_socket(с.фд)
|
||||
}
|
||||
|
||||
фн подключиться*(хост: Строка, порт: Цел64): ТцпСоединение {
|
||||
пусть фд = connect_socket(хост, порт)
|
||||
вернуть ТцпСоединение{ фд: фд }
|
||||
}
|
||||
|
||||
|
||||
140
исх/сеть/хттп/клиент.tri
Normal file
140
исх/сеть/хттп/клиент.tri
Normal file
@@ -0,0 +1,140 @@
|
||||
модуль хттп
|
||||
|
||||
импорт "стд::вывод"
|
||||
импорт "исх/строка"
|
||||
импорт "исх/сеть/тцп"
|
||||
|
||||
фн сериализовать хттп-запрос(хост: Строка, обращение: ХттпОбращение): Строка {
|
||||
пусть метод := обращение.метод
|
||||
если метод = "" {
|
||||
метод := "GET"
|
||||
}
|
||||
|
||||
пусть путь := обращение.путь
|
||||
если путь = "" {
|
||||
путь := "/"
|
||||
}
|
||||
|
||||
пусть первая := строка.ф("$стр $стр HTTP/1.1\r\n", метод, путь)
|
||||
пусть есть длина := ложь
|
||||
пусть выход := первая
|
||||
|
||||
цикл [номер]заглавие среди обращение.заглавия {
|
||||
если заглавие.имя = "Content-Length" { есть длина := истина }
|
||||
выход := строка.собрать(выход, строка.ф("$стр: $стр\r\n", заглавие.имя, заглавие.значение))
|
||||
}
|
||||
|
||||
выход := строка.собрать(выход, строка.ф("Host: $стр\r\n", хост))
|
||||
|
||||
если ~ есть длина {
|
||||
выход := строка.собрать(выход, строка.ф("Content-Length: $цел\r\n", длина(обращение.туловище(:Строка8))))
|
||||
}
|
||||
|
||||
выход := строка.собрать(выход, "\r\n")
|
||||
|
||||
если длина(обращение.туловище) > 0 { выход := строка.собрать(выход, обращение.туловище) }
|
||||
|
||||
вернуть выход
|
||||
}
|
||||
|
||||
фн послать далеко и надолго*(хост: Строка, порт: Цел64, обращение: ХттпОбращение): ХттпОтвет {
|
||||
пусть соединение = тцп.подключиться(хост, порт)
|
||||
пусть данные = сериализовать хттп-запрос(хост, обращение)
|
||||
|
||||
соединение.записать(данные)
|
||||
|
||||
вывод.ф("Ждем хттп ответ\n")
|
||||
пусть ответ = разобрать хттп ответ(соединение)
|
||||
соединение.закрыть()
|
||||
вывод.ф("Дождались\n")
|
||||
|
||||
вернуть ответ
|
||||
}
|
||||
|
||||
фн послать на три буквы*(хост: Строка, порт: Цел64, путь: Строка): ХттпОтвет {
|
||||
вернуть послать далеко и надолго(хост, порт, ХттпОбращение{ метод: "GET", путь: путь })
|
||||
}
|
||||
|
||||
тип Урл* = класс {
|
||||
хост*: Строка := ""
|
||||
порт*: Цел64 := 0
|
||||
путь*: Строка := ""
|
||||
}
|
||||
|
||||
фн парсить урл*(стр: Строка, оплошность := Строка): Урл {
|
||||
оплошность := ""
|
||||
|
||||
пусть с = строка.обрезать пробельные символы(стр)
|
||||
если с = "" {
|
||||
оплошность := "пустой урл"
|
||||
вернуть Урл{}
|
||||
}
|
||||
|
||||
пусть схема := "http"
|
||||
пусть ост := с
|
||||
если строка.разделить(с, "://", схема, ост) {
|
||||
схема := строка.обрезать пробельные символы(схема)
|
||||
} иначе {
|
||||
// без схемы считаем http
|
||||
схема := "http"
|
||||
ост := с
|
||||
}
|
||||
|
||||
// отделяем authority и путь
|
||||
пусть № слеша = строка.индекс(ост, 0, "/")
|
||||
пусть авторитет := ""
|
||||
пусть путь := ""
|
||||
если № слеша >= 0 {
|
||||
пусть ост8 = ост(:Строка8)
|
||||
авторитет := строка.извлечь(ост, 0, № слеша)
|
||||
путь := строка.извлечь(ост, № слеша, длина(ост8) - № слеша)
|
||||
} иначе {
|
||||
авторитет := ост
|
||||
путь := ""
|
||||
}
|
||||
|
||||
авторитет := строка.обрезать пробельные символы(авторитет)
|
||||
если авторитет = "" {
|
||||
оплошность := "пустой хост в урл"
|
||||
вернуть Урл{}
|
||||
}
|
||||
|
||||
// парсим хост и порт
|
||||
пусть хост := авторитет
|
||||
пусть порт: Цел64 := 0
|
||||
пусть № двоеточия = строка.индекс(авторитет, 0, ":")
|
||||
если № двоеточия >= 0 {
|
||||
пусть ав8 = авторитет(:Строка8)
|
||||
хост := строка.извлечь(авторитет, 0, № двоеточия)
|
||||
пусть порт строка := строка.извлечь(авторитет, № двоеточия + 1, длина(ав8) - (№ двоеточия + 1))
|
||||
порт строка := строка.обрезать пробельные символы(порт строка)
|
||||
|
||||
пусть порт значение := 0
|
||||
пусть № байта := 0
|
||||
если ~ строка.извлечь цел(порт строка, № байта, порт значение) {
|
||||
оплошность := "некорректный порт в урл"
|
||||
вернуть Урл{}
|
||||
}
|
||||
если порт значение <= 0 | порт значение > 65535 {
|
||||
оплошность := "порт вне диапазона в урл"
|
||||
вернуть Урл{}
|
||||
}
|
||||
порт := порт значение
|
||||
} иначе {
|
||||
если схема = "https" {
|
||||
порт := 443
|
||||
} иначе {
|
||||
порт := 80
|
||||
}
|
||||
}
|
||||
|
||||
хост := строка.обрезать пробельные символы(хост)
|
||||
если хост = "" {
|
||||
оплошность := "пустой хост в урл"
|
||||
вернуть Урл{}
|
||||
}
|
||||
|
||||
если путь = "" { путь := "/" }
|
||||
|
||||
вернуть Урл{ хост: хост, порт: порт, путь: путь }
|
||||
}
|
||||
120
исх/сеть/хттп/маршрутизатор/маршутизатор.tri
Normal file
120
исх/сеть/хттп/маршрутизатор/маршутизатор.tri
Normal file
@@ -0,0 +1,120 @@
|
||||
модуль маршрутизатор
|
||||
|
||||
импорт "стд::контейнеры/словарь/стр-стр"
|
||||
импорт "исх/строка"
|
||||
импорт "исх/сеть/хттп"
|
||||
импорт "исх/массивы"
|
||||
|
||||
тип Обращение* = класс (хттп.ХттпОбращение) {
|
||||
запрос-в-пути*: стр-стр.Словарь := стр-стр.Словарь{}
|
||||
}
|
||||
|
||||
тип ОбработчикМаршрута = фн (путь: Строка, параметры: массивы.Строки, обращение: Обращение): хттп.ХттпОтвет
|
||||
|
||||
тип Маршрут = класс {
|
||||
путь: Строка := "/"
|
||||
обработчик: ОбработчикМаршрута := позже
|
||||
методы: массивы.Строки := массивы.Строки[]
|
||||
}
|
||||
|
||||
фн (м: Маршрут) подходит по пути(обращение: хттп.ХттпОбращение, параметры := массивы.Строки): Лог {
|
||||
пусть части пути по запросу = строка.разобрать(обращение.путь, "?")
|
||||
пусть части пути обращения = строка.разобрать(части пути по запросу[0], "/")
|
||||
пусть части пути маршрута = строка.разобрать(м.путь, "/")
|
||||
|
||||
цикл [номер]часть пути маршрута среди части пути маршрута {
|
||||
если часть пути маршрута = "*" {
|
||||
пусть ай := номер
|
||||
|
||||
пока ай < длина(части пути обращения) {
|
||||
параметры.добавить(части пути обращения[ай])
|
||||
ай++
|
||||
}
|
||||
|
||||
вернуть истина
|
||||
}
|
||||
|
||||
если номер >= длина(части пути обращения) {
|
||||
вернуть ложь
|
||||
}
|
||||
|
||||
пусть часть пути обращения = части пути обращения[номер]
|
||||
|
||||
если часть пути маршрута = "$" {
|
||||
параметры.добавить(часть пути обращения)
|
||||
} иначе если часть пути маршрута # часть пути обращения {
|
||||
вернуть ложь
|
||||
}
|
||||
}
|
||||
|
||||
вернуть длина(части пути маршрута) = длина(части пути обращения)
|
||||
}
|
||||
|
||||
фн (м: Маршрут) подходит по методу(обращение: хттп.ХттпОбращение): Лог {
|
||||
цикл [номер]метод среди м.методы {
|
||||
если метод = обращение.метод {
|
||||
вернуть истина
|
||||
}
|
||||
}
|
||||
|
||||
вернуть ложь
|
||||
}
|
||||
|
||||
фн (м: Маршрут) подходит для*(обращение: хттп.ХттпОбращение, параметры := массивы.Строки): Лог {
|
||||
вернуть м.подходит по пути(обращение, параметры) & м.подходит по методу(обращение)
|
||||
}
|
||||
|
||||
тип Маршруты = []Маршрут
|
||||
|
||||
тип Маршрутизатор* = класс {
|
||||
маршруты: Маршруты := Маршруты[]
|
||||
обработчик_404: ОбработчикМаршрута := обработчик_404
|
||||
}
|
||||
|
||||
фн (м: Маршрутизатор) добавить маршрут*(путь: Строка, методы: массивы.Строки, обработчик: ОбработчикМаршрута) {
|
||||
м.маршруты.добавить(Маршрут{путь: путь, обработчик: обработчик, методы: методы})
|
||||
}
|
||||
|
||||
фн (м: Маршрутизатор) обработать обращение*(обращение: хттп.ХттпОбращение): хттп.ХттпОтвет {
|
||||
пусть обращение маршрутизатора = Обращение{
|
||||
метод: обращение.метод,
|
||||
путь: обращение.путь,
|
||||
версия: обращение.версия,
|
||||
заглавия: обращение.заглавия,
|
||||
туловище: обращение.туловище,
|
||||
запрос-в-пути: разобрать-запрос-в-пути(обращение.путь)
|
||||
}
|
||||
|
||||
цикл [номер]маршрут среди м.маршруты {
|
||||
пусть параметры := массивы.Строки[]
|
||||
|
||||
если маршрут.подходит для(обращение, параметры) {
|
||||
вернуть маршрут.обработчик(обращение.путь, параметры, обращение маршрутизатора)
|
||||
}
|
||||
}
|
||||
|
||||
вернуть м.обработчик_404(обращение.путь, массивы.Строки[], обращение маршрутизатора)
|
||||
}
|
||||
|
||||
фн разобрать-запрос-в-пути(путь: Строка): стр-стр.Словарь {
|
||||
пусть части = строка.разобрать(путь, "?")
|
||||
|
||||
если длина(части) < 2 {
|
||||
вернуть стр-стр.Словарь{}
|
||||
}
|
||||
|
||||
пусть параметры = строка.разобрать(части[1], "&")
|
||||
пусть словарь = стр-стр.Словарь{}
|
||||
|
||||
цикл [номер]параметр среди параметры {
|
||||
пусть пара = строка.разобрать(параметр, "=")
|
||||
|
||||
если длина(пара) = 2 {
|
||||
словарь.добавить(пара[0], пара[1])
|
||||
} иначе если длина(пара) = 1 {
|
||||
словарь.добавить(пара[0], "")
|
||||
}
|
||||
}
|
||||
|
||||
вернуть словарь
|
||||
}
|
||||
8
исх/сеть/хттп/маршрутизатор/обработчики.tri
Normal file
8
исх/сеть/хттп/маршрутизатор/обработчики.tri
Normal file
@@ -0,0 +1,8 @@
|
||||
модуль маршрутизатор
|
||||
|
||||
импорт "исх/массивы"
|
||||
импорт "исх/сеть/хттп"
|
||||
|
||||
фн обработчик_404*(путь: Строка, параметры: массивы.Строки, обращение: Обращение): хттп.ХттпОтвет {
|
||||
вернуть хттп.ответ_404()
|
||||
}
|
||||
118
исх/сеть/хттп/ответ.tri
Normal file
118
исх/сеть/хттп/ответ.tri
Normal file
@@ -0,0 +1,118 @@
|
||||
модуль хттп
|
||||
|
||||
фн ответ_201*(): ХттпОтвет {
|
||||
вернуть ХттпОтвет{
|
||||
код: 201,
|
||||
состояние: "Created",
|
||||
туловище: "Тварь успешно создана.",
|
||||
}
|
||||
}
|
||||
|
||||
фн ответ_204*(): ХттпОтвет {
|
||||
вернуть ХттпОтвет{
|
||||
код: 204,
|
||||
состояние: "No Content",
|
||||
туловище: "Пожалуйста, оставайтесь на месте. За вами уже выехали.",
|
||||
}
|
||||
}
|
||||
|
||||
фн ответ_400*(): ХттпОтвет {
|
||||
вернуть ХттпОтвет{
|
||||
код: 400,
|
||||
состояние: "Bad Request",
|
||||
туловище: "Некорректный запрос. Пожалуйста, проверьте правильность запроса и повторите попытку.",
|
||||
}
|
||||
}
|
||||
|
||||
фн ответ_401*(): ХттпОтвет {
|
||||
вернуть ХттпОтвет{
|
||||
код: 401,
|
||||
состояние: "Unauthorized",
|
||||
туловище: "Требуется аутентификация. Пожалуйста, предоставьте свои паспортные данные и повторите запрос.",
|
||||
}
|
||||
}
|
||||
|
||||
фн ответ_402*(): ХттпОтвет {
|
||||
вернуть ХттпОтвет{
|
||||
код: 402,
|
||||
состояние: "Payment Required",
|
||||
туловище: "Доступ к запрашиваемому ресурсу требует оплаты. Пожалуйста, свяжитесь с администратором для получения дополнительной информации.",
|
||||
}
|
||||
}
|
||||
|
||||
фн ответ_403*(): ХттпОтвет {
|
||||
вернуть ХттпОтвет{
|
||||
код: 403,
|
||||
состояние: "Forbidden",
|
||||
туловище: "Вы были репрессированы. Пожалуйста, перейдите по ссылке: http://сибирь.рф",
|
||||
}
|
||||
}
|
||||
|
||||
фн ответ_422*(): ХттпОтвет {
|
||||
вернуть ХттпОтвет{
|
||||
код: 422,
|
||||
состояние: "Unprocessable Entity",
|
||||
туловище: "Неперевариваемая тварь.",
|
||||
}
|
||||
}
|
||||
|
||||
фн ответ_404*(): ХттпОтвет {
|
||||
вернуть ХттпОтвет{
|
||||
код: 404,
|
||||
состояние: "Not Found",
|
||||
туловище: "Запрашиваемый ресурс не найден на сервере.",
|
||||
}
|
||||
}
|
||||
|
||||
фн ответ_500*(): ХттпОтвет {
|
||||
вернуть ХттпОтвет{
|
||||
код: 500,
|
||||
состояние: "Internal Server Error",
|
||||
туловище: "Просим быть внимательными и бдительными. Оглядывайтесь вверх и по сторонам. Что-то произошло непонятное.",
|
||||
}
|
||||
}
|
||||
|
||||
фн создать ответ*(база: ХттпОтвет, расширение: ХттпОтвет): ХттпОтвет {
|
||||
пусть пустой ответ = ХттпОтвет{}
|
||||
пусть ответ = ХттпОтвет{}
|
||||
|
||||
если расширение.код # пустой ответ.код {
|
||||
ответ.код := расширение.код
|
||||
} иначе {
|
||||
ответ.код := база.код
|
||||
}
|
||||
|
||||
если расширение.состояние # пустой ответ.состояние {
|
||||
ответ.состояние := расширение.состояние
|
||||
} иначе {
|
||||
ответ.состояние := база.состояние
|
||||
}
|
||||
|
||||
цикл [номер]заглавие среди база.заглавия {
|
||||
ответ.заглавия.добавить(заглавие)
|
||||
}
|
||||
|
||||
цикл [номер]заглавие среди расширение.заглавия {
|
||||
пусть нашлось := ложь
|
||||
|
||||
цикл [уемер]существующее среди ответ.заглавия {
|
||||
если заглавие.имя = существующее.имя {
|
||||
существующее.значение := заглавие.значение
|
||||
нашлось := истина
|
||||
прервать
|
||||
}
|
||||
}
|
||||
|
||||
если ~нашлось {
|
||||
ответ.заглавия.добавить(заглавие)
|
||||
}
|
||||
}
|
||||
|
||||
если расширение.туловище # "" {
|
||||
ответ.туловище := расширение.туловище
|
||||
} иначе {
|
||||
ответ.туловище := база.туловище
|
||||
}
|
||||
|
||||
вернуть ответ
|
||||
}
|
||||
235
исх/сеть/хттп/парсер.tri
Normal file
235
исх/сеть/хттп/парсер.tri
Normal file
@@ -0,0 +1,235 @@
|
||||
модуль хттп
|
||||
|
||||
импорт "исх/строка"
|
||||
импорт "исх/вперед-назад"
|
||||
импорт "исх/сеть/тцп"
|
||||
|
||||
фн сериализовать хттп ответ*(р: ХттпОтвет): Строка {
|
||||
пусть ответ := строка.собрать(строка.ф("$стр $цел $стр\r\n", р.версия, р.код, р.состояние))
|
||||
|
||||
пусть есть размер контента := ложь
|
||||
|
||||
цикл [номер]заглавие среди р.заглавия {
|
||||
если заглавие.имя = "Content-Length" { есть размер контента := истина }
|
||||
ответ := строка.собрать(ответ, строка.ф("$стр: $стр\r\n", заглавие.имя, заглавие.значение))
|
||||
}
|
||||
|
||||
если ~ есть размер контента {
|
||||
ответ := строка.собрать(ответ, строка.ф("Content-Length: $цел\r\n", длина(р.туловище(:Строка8))))
|
||||
}
|
||||
|
||||
ответ := строка.собрать(ответ, "\r\n")
|
||||
|
||||
если длина(р.туловище) > 0 {
|
||||
ответ := строка.собрать(ответ, р.туловище)
|
||||
}
|
||||
|
||||
вернуть ответ
|
||||
}
|
||||
|
||||
фн отправить хттп ответ*(с: тцп.ТцпСоединение, р: ХттпОтвет) {
|
||||
пусть данные := сериализовать хттп ответ(р)
|
||||
с.записать(данные)
|
||||
}
|
||||
|
||||
фн разобрать хттп обращение*(с: вперед-назад.Крипипаста): ХттпОбращение {
|
||||
пусть сколько читаем = 1024
|
||||
пусть прочитано := 0
|
||||
пусть обращение = ХттпОбращение{}
|
||||
пусть данные := ""
|
||||
пусть первая линия := ""
|
||||
пусть добрались до тела := ложь
|
||||
пусть размер контента: Цел64 := -1
|
||||
|
||||
пока истина {
|
||||
пусть сколько прочитать: Цел64 := -1
|
||||
если размер контента > 0 & добрались до тела {
|
||||
сколько прочитать := размер контента - прочитано
|
||||
}
|
||||
|
||||
если сколько прочитать = 0 {
|
||||
вернуть обращение
|
||||
}
|
||||
|
||||
пусть новые данные = с.прочитать(сколько читаем)
|
||||
прочитано := прочитано + длина(новые данные)
|
||||
если длина(новые данные) = 0 {
|
||||
вернуть обращение
|
||||
}
|
||||
|
||||
данные := строка.собрать(данные, новые данные)
|
||||
|
||||
если ~ добрались до тела {
|
||||
пока длина(данные) > 0 {
|
||||
пусть конец строки = строка.индекс(данные, 0, "\n")
|
||||
|
||||
если конец строки = -1 {
|
||||
прервать
|
||||
}
|
||||
|
||||
пусть линия = строка.обрезать пробельные символы(строка.извлечь(данные, 0, конец строки))
|
||||
данные := строка.извлечь(данные, конец строки + 1, длина(данные(:Строка8)) - конец строки)
|
||||
|
||||
если линия = "" {
|
||||
если размер контента > 0 {
|
||||
пусть индекс переноса = строка.индекс(данные, 0, "\n")
|
||||
|
||||
добрались до тела := истина
|
||||
данные := строка.извлечь(данные, индекс переноса + 1, длина(данные(:Строка8)) - индекс переноса)
|
||||
прочитано := длина(данные(:Строка8))
|
||||
обращение.туловище := данные
|
||||
данные := ""
|
||||
|
||||
прервать
|
||||
} иначе {
|
||||
вернуть обращение
|
||||
}
|
||||
}
|
||||
|
||||
если первая линия = "" {
|
||||
первая линия := линия
|
||||
|
||||
пусть части = строка.разобрать(первая линия, " ")
|
||||
|
||||
если длина(части) >= 1 { обращение.метод := части[0] }
|
||||
если длина(части) >= 2 {
|
||||
цикл [номер]часть среди части {
|
||||
если номер > 0 & номер < длина(части) - 1 {
|
||||
если номер > 1 {
|
||||
обращение.путь := строка.собрать(обращение.путь, " ")
|
||||
}
|
||||
|
||||
обращение.путь := строка.собрать(обращение.путь, часть)
|
||||
}
|
||||
}
|
||||
}
|
||||
если длина(части) >= 3 { обращение.версия := части[длина(части) - 1] }
|
||||
} иначе {
|
||||
пусть заглавие = ХттпЗаглавие{}
|
||||
|
||||
строка.разделить(линия, ":", заглавие.имя, заглавие.значение)
|
||||
|
||||
заглавие.имя := строка.обрезать пробельные символы(заглавие.имя)
|
||||
заглавие.значение := строка.обрезать пробельные символы(заглавие.значение)
|
||||
|
||||
если размер контента < 0 & заглавие.имя = "Content-Length" {
|
||||
пусть новый размер контента := 0
|
||||
пусть номер байта := 0
|
||||
|
||||
если строка.извлечь цел(заглавие.значение, номер байта, новый размер контента) {
|
||||
размер контента := новый размер контента
|
||||
}
|
||||
}
|
||||
|
||||
обращение.заглавия.добавить(заглавие)
|
||||
}
|
||||
}
|
||||
} иначе {
|
||||
обращение.туловище := строка.соединить(обращение.туловище, данные)
|
||||
}
|
||||
}
|
||||
|
||||
вернуть обращение
|
||||
}
|
||||
|
||||
фн разобрать хттп ответ*(с: тцп.ТцпСоединение): ХттпОтвет {
|
||||
пусть сколько читаем = 1024
|
||||
пусть прочитано := 0
|
||||
пусть ответ = ХттпОтвет{}
|
||||
пусть данные := ""
|
||||
пусть первая линия := ""
|
||||
пусть добрались до тела := ложь
|
||||
пусть размер контента: Цел64 := -1
|
||||
|
||||
пока истина {
|
||||
пусть сколько прочитать: Цел64 := -1
|
||||
если размер контента > 0 & добрались до тела {
|
||||
сколько прочитать := размер контента - прочитано
|
||||
}
|
||||
|
||||
если сколько прочитать = 0 {
|
||||
вернуть ответ
|
||||
}
|
||||
|
||||
пусть новые данные = с.прочитать(сколько читаем)
|
||||
прочитано := прочитано + длина(новые данные)
|
||||
если длина(новые данные) = 0 {
|
||||
вернуть ответ
|
||||
}
|
||||
|
||||
данные := строка.собрать(данные, новые данные)
|
||||
|
||||
если ~ добрались до тела {
|
||||
пока длина(данные) > 0 {
|
||||
пусть конец строки = строка.индекс(данные, 0, "\n")
|
||||
|
||||
если конец строки = -1 {
|
||||
прервать
|
||||
}
|
||||
|
||||
пусть линия = строка.обрезать пробельные символы(строка.извлечь(данные, 0, конец строки))
|
||||
данные := строка.извлечь(данные, конец строки + 1, длина(данные(:Строка8)) - конец строки)
|
||||
|
||||
если линия = "" {
|
||||
если размер контента > 0 {
|
||||
добрались до тела := истина
|
||||
прочитано := длина(данные(:Строка8))
|
||||
ответ.туловище := данные
|
||||
данные := ""
|
||||
|
||||
прервать
|
||||
} иначе {
|
||||
вернуть ответ
|
||||
}
|
||||
}
|
||||
|
||||
если первая линия = "" {
|
||||
первая линия := линия
|
||||
|
||||
пусть части = строка.разобрать(первая линия, " ")
|
||||
|
||||
если длина(части) >= 1 { ответ.версия := части[0] }
|
||||
если длина(части) >= 2 {
|
||||
пусть новый код := 0
|
||||
пусть номер байта := 0
|
||||
если строка.извлечь цел(части[1], номер байта, новый код) {
|
||||
ответ.код := новый код
|
||||
}
|
||||
}
|
||||
если длина(части) >= 3 {
|
||||
цикл [номер]часть среди части {
|
||||
если номер >= 2 {
|
||||
если номер > 2 {
|
||||
ответ.состояние := строка.собрать(ответ.состояние, " ")
|
||||
}
|
||||
ответ.состояние := строка.собрать(ответ.состояние, часть)
|
||||
}
|
||||
}
|
||||
}
|
||||
} иначе {
|
||||
пусть заглавие = ХттпЗаглавие{}
|
||||
|
||||
строка.разделить(линия, ":", заглавие.имя, заглавие.значение)
|
||||
|
||||
заглавие.имя := строка.обрезать пробельные символы(заглавие.имя)
|
||||
заглавие.значение := строка.обрезать пробельные символы(заглавие.значение)
|
||||
|
||||
если размер контента < 0 & заглавие.имя = "Content-Length" {
|
||||
пусть новый размер контента := 0
|
||||
пусть номер байта := 0
|
||||
|
||||
если строка.извлечь цел(заглавие.значение, номер байта, новый размер контента) {
|
||||
размер контента := новый размер контента
|
||||
}
|
||||
}
|
||||
|
||||
ответ.заглавия.добавить(заглавие)
|
||||
}
|
||||
}
|
||||
} иначе {
|
||||
ответ.туловище := строка.соединить(ответ.туловище, данные)
|
||||
}
|
||||
}
|
||||
|
||||
вернуть ответ
|
||||
}
|
||||
24
исх/сеть/хттп/типы.tri
Normal file
24
исх/сеть/хттп/типы.tri
Normal file
@@ -0,0 +1,24 @@
|
||||
модуль хттп
|
||||
|
||||
тип ХттпЗаглавие* = класс {
|
||||
имя*: Строка := ""
|
||||
значение*: Строка := ""
|
||||
}
|
||||
|
||||
тип ХттпЗаглавия* = []ХттпЗаглавие
|
||||
|
||||
тип ХттпОбращение* = класс {
|
||||
метод*: Строка := ""
|
||||
путь*: Строка := ""
|
||||
версия*: Строка := ""
|
||||
заглавия*: ХттпЗаглавия := ХттпЗаглавия[]
|
||||
туловище*: Строка := ""
|
||||
}
|
||||
|
||||
тип ХттпОтвет* = класс {
|
||||
версия*: Строка := "HTTP/1.1"
|
||||
код*: Цел64 := 200
|
||||
состояние*: Строка := "OK"
|
||||
заглавия*: ХттпЗаглавия := ХттпЗаглавия[]
|
||||
туловище*: Строка := ""
|
||||
}
|
||||
9
исх/спринтф/спринтф.tri
Normal file
9
исх/спринтф/спринтф.tri
Normal file
@@ -0,0 +1,9 @@
|
||||
модуль спринтф
|
||||
|
||||
импорт "стд::строки"
|
||||
|
||||
фн ф*(формат: Строка, список: ...*): Строка {
|
||||
пусть сб = строки.Сборщик{}
|
||||
сб.ф(формат, список...)
|
||||
вернуть сб.строка()
|
||||
}
|
||||
78
исх/сраб.tri
Normal file
78
исх/сраб.tri
Normal file
@@ -0,0 +1,78 @@
|
||||
модуль сраб
|
||||
|
||||
импорт "стд::вывод"
|
||||
импорт "стд::комстрока"
|
||||
импорт "исх/спринтф"
|
||||
импорт "исх/струя"
|
||||
импорт "исх/сеть/тцп"
|
||||
импорт "исх/сеть/хттп"
|
||||
импорт "исх/маршруты"
|
||||
импорт "исх/сборщик-мусора"
|
||||
импорт "исх/миграции"
|
||||
импорт "исх/картотека"
|
||||
импорт "исх/вперед-назад"
|
||||
импорт "исх/стд-вперед-назад"
|
||||
импорт "исх/отдых"
|
||||
|
||||
пусть маршрутизатор = маршруты.получить маршрутизатор()
|
||||
|
||||
фн обработать тцп подключение(соединение полиморф: *) {
|
||||
пусть соединение = соединение полиморф(:тцп.ТцпСоединение)
|
||||
пусть обращение = хттп.разобрать хттп обращение(соединение)
|
||||
пусть ответ = маршрутизатор.обработать обращение(обращение)
|
||||
|
||||
// вывод.ф("$стр $стр -> $цел\n", обращение.метод, обращение.путь, ответ.код)
|
||||
|
||||
хттп.отправить хттп ответ(соединение, ответ)
|
||||
соединение.закрыть()
|
||||
}
|
||||
|
||||
фн обработать стдвнутрь подключение() {
|
||||
пусть обращение = хттп.разобрать хттп обращение(стд-вперед-назад.СтдВнутрь{})
|
||||
|
||||
// вывод.ф("$стр $стр\n", обращение.метод, обращение.путь)
|
||||
|
||||
пусть ответ = маршрутизатор.обработать обращение(обращение)
|
||||
пусть данные = хттп.сериализовать хттп ответ(ответ)
|
||||
|
||||
стд-вперед-назад.ошибка(данные)
|
||||
}
|
||||
|
||||
вход {
|
||||
комстрока.логическая настройка("подшефный", ложь, "")
|
||||
комстрока.логическая настройка("роанапур", ложь, "")
|
||||
комстрока.разобрать()
|
||||
|
||||
пусть подшефный = комстрока.логическое значение("подшефный")
|
||||
пусть роанапур = комстрока.логическое значение("роанапур")
|
||||
|
||||
если подшефный {
|
||||
обработать стдвнутрь подключение()
|
||||
} иначе если роанапур {
|
||||
миграции.мигрировать(картотека.зайти())
|
||||
} иначе {
|
||||
миграции.мигрировать(картотека.зайти())
|
||||
|
||||
пусть номер причала = 1337
|
||||
|
||||
вывод.ф("Готовим сервер у причала $цел\n", номер причала)
|
||||
|
||||
пусть сервер = тцп.создать сервер(номер причала)
|
||||
пусть обработано запросов := 0
|
||||
|
||||
пока истина {
|
||||
пусть подключение = сервер.принять чертово соединение()
|
||||
пусть новая струя = струя.новая струя(обработать тцп подключение, подключение)
|
||||
струя.отсоединить струю(новая струя)
|
||||
|
||||
обработано запросов++
|
||||
|
||||
если обработано запросов > 100000 {
|
||||
вывод.ф("Вы используете пробную версию программы. Пожалуйста, приобретите полную версию для продолжения использования.\n")
|
||||
прервать
|
||||
}
|
||||
}
|
||||
|
||||
вывод.ф("Котенок умер\n")
|
||||
}
|
||||
}
|
||||
23
исх/стд-вперед-назад/ввод.tri
Normal file
23
исх/стд-вперед-назад/ввод.tri
Normal file
@@ -0,0 +1,23 @@
|
||||
модуль стд-вперед-назад
|
||||
|
||||
// c:include "stdin.h"
|
||||
|
||||
фн stdin_read_to_string(bytes: Цел64): Строка @внеш
|
||||
фн stderr_write_string(data: Строка) @внеш
|
||||
|
||||
тип СтдВнутрь* = класс {
|
||||
|
||||
}
|
||||
|
||||
фн (внутрь: СтдВнутрь) прочитать*(сколько: Цел64): Строка {
|
||||
вернуть прочитать(сколько)
|
||||
}
|
||||
|
||||
фн прочитать*(сколько: Цел64): Строка {
|
||||
вернуть stdin_read_to_string(сколько)
|
||||
}
|
||||
|
||||
фн ошибка*(данные: Строка) {
|
||||
stderr_write_string(данные)
|
||||
}
|
||||
|
||||
184
исх/строка/строка.tri
Normal file
184
исх/строка/строка.tri
Normal file
@@ -0,0 +1,184 @@
|
||||
модуль строка
|
||||
|
||||
импорт "стд::строки"
|
||||
импорт "стд::юникод"
|
||||
импорт "исх/массивы"
|
||||
|
||||
тип Байты = []Байт
|
||||
|
||||
фн tri_substring(с: Строка8, первый-байт: Цел64, число-байтов: Цел64): Строка @внеш
|
||||
фн tri_substring_from_bytes(байты: Байты, первый-байт: Цел64, число-байтов: Цел64): Строка @внеш
|
||||
|
||||
фн заменить*(с: Строка, подстрока: Строка, замена: Строка): Строка {
|
||||
надо длина(подстрока) > 0 иначе вернуть с
|
||||
|
||||
пусть с8 = с(:Строка8)
|
||||
пусть п8 = подстрока(:Строка8)
|
||||
|
||||
пусть № := индекс(с, 0, подстрока)
|
||||
надо № >= 0 иначе вернуть с
|
||||
|
||||
пусть сб = строки.Сборщик{}
|
||||
пусть №-старт := 0
|
||||
пока истина {
|
||||
сб.добавить строку(строки.извлечь(с8(:Строка), №-старт, № - №-старт))
|
||||
сб.добавить строку(замена)
|
||||
|
||||
№-старт := № + длина(п8)
|
||||
№ := индекс(с, №-старт, подстрока)
|
||||
надо № >= 0 иначе прервать
|
||||
надо №-старт < длина(замена) иначе прервать
|
||||
}
|
||||
сб.добавить строку(строки.извлечь(с8(:Строка), №-старт, длина(с8) - №-старт))
|
||||
|
||||
вернуть сб.строка()
|
||||
}
|
||||
|
||||
фн разобрать*(с: Строка, разделитель: Строка): массивы.Строки {
|
||||
пусть р8 = разделитель(:Строка8)
|
||||
|
||||
выбор длина(р8) {
|
||||
когда 0: вернуть массивы.Строки[с]
|
||||
когда 1:
|
||||
вернуть разобрать1(с, р8[0])
|
||||
другое
|
||||
авария("не реализовано - длина разделителя > 1")
|
||||
}
|
||||
вернуть массивы.Строки[]
|
||||
}
|
||||
|
||||
фн соединить*(разделитель: Строка, строчки: ...Строка): Строка {
|
||||
вернуть строки.соединить(разделитель, строчки...)
|
||||
}
|
||||
|
||||
фн ф*(формат: Строка, аргументы: ...*): Строка {
|
||||
пусть сб = строки.Сборщик{}
|
||||
сб.ф(формат, аргументы...)
|
||||
вернуть сб.строка()
|
||||
}
|
||||
|
||||
фн разобрать1(с: Строка, разделитель: Байт): массивы.Строки {
|
||||
пусть рез = массивы.Строки[]
|
||||
пусть с8 = с(:Строка8)
|
||||
пусть № := 0
|
||||
пусть №-разд := -1
|
||||
пока № < длина(с8) {
|
||||
если с8[№] = разделитель {
|
||||
если №-разд + 1 = № {
|
||||
рез.добавить("")
|
||||
} иначе {
|
||||
рез.добавить(tri_substring(с8, №-разд+1, № - №-разд - 1))
|
||||
}
|
||||
№-разд := №
|
||||
}
|
||||
№++
|
||||
}
|
||||
рез.добавить(tri_substring(с8, №-разд+1, длина(с8) - №-разд - 1))
|
||||
|
||||
вернуть рез
|
||||
}
|
||||
|
||||
фн собрать*(список строк: ...Строка): Строка {
|
||||
надо длина(список строк) > 0 иначе вернуть ""
|
||||
|
||||
пусть размер := 0
|
||||
пусть № := 0
|
||||
пока № < длина(список строк) {
|
||||
размер := размер + длина(список строк[№](:Строка8))
|
||||
№++
|
||||
}
|
||||
|
||||
пусть сб = строки.Сборщик{}
|
||||
№ := 0
|
||||
пока № < длина(список строк) {
|
||||
сб.добавить строку(список строк[№])
|
||||
№++
|
||||
}
|
||||
|
||||
вернуть сб.строка()
|
||||
}
|
||||
|
||||
фн индекс*(с: Строка, №-старт: Цел64, подстрока: Строка): Цел64 {
|
||||
вернуть строки.индекс(с, №-старт, подстрока)
|
||||
}
|
||||
|
||||
фн извлечь*(с: Строка, №-байта: Цел64, число-байтов: Цел64): Строка {
|
||||
вернуть строки.извлечь(с, №-байта, число-байтов)
|
||||
}
|
||||
|
||||
фн обрезать пробельные символы*(с: Строка): Строка {
|
||||
|
||||
пусть с8 = с(:Строка8)
|
||||
пусть №1 := 0
|
||||
пока №1 < длина(с8) {
|
||||
надо с8[№1] < 0x80(:Байт) иначе прервать
|
||||
надо юникод.пробельный символ?(с8[№1](:Символ)) иначе прервать
|
||||
№1++
|
||||
}
|
||||
|
||||
пусть №2 := длина(с8)
|
||||
пока №2 > №1 {
|
||||
пусть байт = с8[№2-1]
|
||||
надо байт < 0x80(:Байт) иначе прервать
|
||||
надо юникод.пробельный символ?(байт(:Символ)) иначе прервать
|
||||
№2--
|
||||
}
|
||||
|
||||
вернуть tri_substring(с8, №1, №2 - №1)
|
||||
}
|
||||
|
||||
фн разделить*(с: Строка, разделитель: Строка, первая := Строка, вторая := Строка): Лог {
|
||||
|
||||
пусть и = индекс(с, 0, разделитель)
|
||||
надо и >= 0 иначе {
|
||||
первая := с
|
||||
вторая := ""
|
||||
вернуть ложь
|
||||
}
|
||||
|
||||
пусть с8 = с(:Строка8)
|
||||
пусть р8 = разделитель(:Строка8)
|
||||
|
||||
первая := tri_substring(с8, 0, и)
|
||||
вторая := tri_substring(с8, и + длина(р8), длина(с8) - (и +длина(р8)))
|
||||
|
||||
вернуть истина
|
||||
}
|
||||
|
||||
фн извлечь цел*(с: Строка, №-байта := Цел64, рез := Цел64): Лог {
|
||||
рез := 0
|
||||
|
||||
пусть с8 = с(:Строка8)
|
||||
надо №-байта < длина(с8) иначе вернуть ложь
|
||||
|
||||
пусть нег = с8[№-байта] = '-'(:Байт)
|
||||
если нег | с8[№-байта] = '+'(:Байт) {
|
||||
№-байта++
|
||||
надо №-байта < длина(с8) иначе вернуть ложь
|
||||
}
|
||||
|
||||
пусть сим := с8[№-байта](:Символ)
|
||||
надо сим >= '0' & сим <= '9' иначе вернуть ложь
|
||||
|
||||
пусть число := 0
|
||||
пока истина {
|
||||
пусть цифра = сим(:Цел64) - '0'(:Цел64)
|
||||
|
||||
// проверка выхода за границу
|
||||
надо число <= (0x7FFFFFFFFFFFFFFF(:Цел64) - цифра) / 10 иначе вернуть ложь
|
||||
|
||||
число := число*10 + цифра
|
||||
№-байта++
|
||||
если №-байта >= длина(с8) {
|
||||
если нег {
|
||||
число := - число
|
||||
}
|
||||
рез := число
|
||||
вернуть истина
|
||||
}
|
||||
сим := с8[№-байта](:Символ)
|
||||
|
||||
надо сим >= '0' & сим <= '9' иначе прервать
|
||||
}
|
||||
вернуть ложь
|
||||
}
|
||||
3
исх/струя/струя-внутр/внутр.tri
Normal file
3
исх/струя/струя-внутр/внутр.tri
Normal file
@@ -0,0 +1,3 @@
|
||||
модуль струя-внутр
|
||||
|
||||
тип Струя* = фн (аргумент: *)
|
||||
21
исх/струя/струя.tri
Normal file
21
исх/струя/струя.tri
Normal file
@@ -0,0 +1,21 @@
|
||||
модуль струя
|
||||
|
||||
импорт "исх/струя/струя-внутр"
|
||||
|
||||
// c:include "pstruya.h"
|
||||
|
||||
фн tri_thread_create(струя: струя-внутр.Струя, аргумент: *): Цел64 @внеш
|
||||
фн tri_thread_join(ид: Цел64) @внеш
|
||||
фн tri_thread_detach(ид: Цел64) @внеш
|
||||
|
||||
фн новая струя*(струя: струя-внутр.Струя, аргумент: *): Цел64 {
|
||||
вернуть tri_thread_create(струя, аргумент)
|
||||
}
|
||||
|
||||
фн ждать струю*(ид: Цел64) {
|
||||
tri_thread_join(ид)
|
||||
}
|
||||
|
||||
фн отсоединить струю*(ид: Цел64) {
|
||||
tri_thread_detach(ид)
|
||||
}
|
||||
296
исх/форматы/джесон/лексер.tri
Normal file
296
исх/форматы/джесон/лексер.tri
Normal file
@@ -0,0 +1,296 @@
|
||||
модуль джесон
|
||||
|
||||
импорт "стд::строки"
|
||||
импорт "исх/массивы"
|
||||
импорт "исх/спринтф"
|
||||
|
||||
// да, это тоже цифры. просто поверьте
|
||||
пусть цифры = массивы.Строки["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "+"]
|
||||
|
||||
тип ДжесонТокен = класс {
|
||||
|
||||
}
|
||||
|
||||
фн (токен: ДжесонТокен) в строку(): Строка {
|
||||
вернуть "пустой токен. где вы его взяли вообще?"
|
||||
}
|
||||
|
||||
тип ДжесонТокены = []ДжесонТокен
|
||||
|
||||
фн массив токенов в строку(токены: ДжесонТокены): Строка {
|
||||
пусть рез := ""
|
||||
|
||||
цикл [номер]токен среди токены {
|
||||
рез := строки.собрать(рез, токен.в строку())
|
||||
}
|
||||
|
||||
вернуть рез
|
||||
}
|
||||
|
||||
тип ТокенФигурнаяСкобка = класс(ДжесонТокен) {
|
||||
закрывающая: Лог := ложь
|
||||
}
|
||||
|
||||
фн (токен: ТокенФигурнаяСкобка) в строку(): Строка {
|
||||
если токен.закрывающая {
|
||||
вернуть "}"
|
||||
} иначе {
|
||||
вернуть "{"
|
||||
}
|
||||
}
|
||||
|
||||
тип ТокенКвадратнаяСкобка = класс(ДжесонТокен) {
|
||||
закрывающая: Лог := ложь
|
||||
}
|
||||
|
||||
фн (токен: ТокенКвадратнаяСкобка) в строку(): Строка {
|
||||
если токен.закрывающая {
|
||||
вернуть "]"
|
||||
} иначе {
|
||||
вернуть "["
|
||||
}
|
||||
}
|
||||
|
||||
тип ТокенЗапятая = класс(ДжесонТокен) {
|
||||
|
||||
}
|
||||
|
||||
фн (токен: ТокенЗапятая) в строку(): Строка {
|
||||
вернуть ","
|
||||
}
|
||||
|
||||
тип ТокенДвоеточие = класс(ДжесонТокен) {
|
||||
|
||||
}
|
||||
|
||||
фн (токен: ТокенДвоеточие) в строку(): Строка {
|
||||
вернуть ":"
|
||||
}
|
||||
|
||||
тип ТокенЧисло = класс(ДжесонТокен) {
|
||||
значение: Цел64 := 0
|
||||
}
|
||||
|
||||
фн (токен: ТокенЧисло) в строку(): Строка {
|
||||
вернуть спринтф.ф("$цел", токен.значение)
|
||||
}
|
||||
|
||||
тип ТокенСтрока = класс(ДжесонТокен) {
|
||||
значение: Строка := ""
|
||||
}
|
||||
|
||||
фн (токен: ТокенСтрока) в строку(): Строка {
|
||||
пусть строка := строки.заменить все(токен.значение, "\\", "\\\\")
|
||||
строка := строки.заменить все(строка, "\"", "\\\"")
|
||||
|
||||
вернуть спринтф.ф("\"$стр\"", строка)
|
||||
}
|
||||
|
||||
тип ТокенБульБуль = класс(ДжесонТокен) {
|
||||
значение: Лог := ложь
|
||||
}
|
||||
|
||||
фн (токен: ТокенБульБуль) в строку(): Строка {
|
||||
если токен.значение {
|
||||
вернуть "true"
|
||||
} иначе {
|
||||
вернуть "false"
|
||||
}
|
||||
}
|
||||
|
||||
фн съесть символ(стр := Строка, ошибка := Строка): Строка {
|
||||
пусть символ = посмотреть но не трогать(стр, ошибка)
|
||||
если ошибка # "" { вернуть "" }
|
||||
|
||||
стр := строки.извлечь(стр, 1, длина(стр(:Строка8)) - 1)
|
||||
вернуть символ
|
||||
}
|
||||
|
||||
фн съесть конкретный символ(стр := Строка, ожидаемый символ: Строка, ошибка := Строка): Строка {
|
||||
пусть символ = посмотреть конкретный символ но не трогать(стр, ожидаемый символ, ошибка)
|
||||
если ошибка # "" { вернуть "" }
|
||||
|
||||
стр := строки.извлечь(стр, 1, длина(стр(:Строка8)) - 1)
|
||||
вернуть символ
|
||||
}
|
||||
|
||||
фн посмотреть но не трогать(стр := Строка, ошибка := Строка): Строка {
|
||||
если длина(стр) = 0 {
|
||||
ошибка := "нежданный конец строки"
|
||||
вернуть ""
|
||||
}
|
||||
|
||||
пусть символ := строки.извлечь(стр, 0, 1)
|
||||
вернуть символ
|
||||
}
|
||||
|
||||
фн посмотреть конкретный символ но не трогать (стр := Строка, ожидаемый символ: Строка, ошибка := Строка): Строка {
|
||||
если длина(стр) = 0 {
|
||||
ошибка := спринтф.ф("нежданный конец строки, ожидался символ '$символ'", ожидаемый символ)
|
||||
вернуть ""
|
||||
}
|
||||
|
||||
пусть символ = строки.извлечь(стр, 0, 1)
|
||||
если символ # ожидаемый символ {
|
||||
ошибка := спринтф.ф("ожидался символ '$стр', а пришёл '$символ'", ожидаемый символ, символ)
|
||||
вернуть ""
|
||||
}
|
||||
|
||||
вернуть символ
|
||||
}
|
||||
|
||||
фн читать число(стр := Строка, ошибка := Строка): Цел64 {
|
||||
пусть число := ""
|
||||
|
||||
пока истина {
|
||||
пусть символ = посмотреть но не трогать(стр, ошибка)
|
||||
если ошибка # "" { вернуть 0 }
|
||||
|
||||
пусть является цифрой := ложь
|
||||
пусть является знаком := ложь
|
||||
|
||||
цикл [номер]цифра среди цифры {
|
||||
если символ = цифра {
|
||||
является цифрой := истина
|
||||
прервать
|
||||
}
|
||||
}
|
||||
|
||||
если является цифрой {
|
||||
число := строки.собрать(число, символ)
|
||||
стр := строки.извлечь(стр, 1, длина(стр(:Строка8)) - 1)
|
||||
} иначе {
|
||||
если длина(число) = 0 {
|
||||
ошибка := спринтф.ф("ожидалось число, а пришёл '$символ'", символ)
|
||||
вернуть 0
|
||||
}
|
||||
|
||||
пусть целое := 0
|
||||
пусть номер байта зачем он тебе нужен вообще глупая машина := 0
|
||||
пусть мне повезло = строки.извлечь цел(число, номер байта зачем он тебе нужен вообще глупая машина, целое)
|
||||
|
||||
если ~мне повезло {
|
||||
ошибка := спринтф.ф("ошибка преобразования числа '$число'", число)
|
||||
}
|
||||
|
||||
вернуть целое
|
||||
}
|
||||
}
|
||||
|
||||
вернуть 0
|
||||
}
|
||||
|
||||
фн читать строку(стр := Строка, ошибка := Строка): Строка {
|
||||
съесть конкретный символ(стр, "\"", ошибка)
|
||||
если ошибка # "" { вернуть "" }
|
||||
|
||||
пусть экран := ложь
|
||||
пусть строка := ""
|
||||
|
||||
пока истина {
|
||||
пусть символ = съесть символ(стр, ошибка)
|
||||
если ошибка # "" { вернуть "" }
|
||||
|
||||
если символ = "\\" {
|
||||
экран := ~экран
|
||||
} иначе если символ = "\"" & ~экран {
|
||||
вернуть строка
|
||||
} иначе {
|
||||
экран := ложь
|
||||
строка := строки.собрать(строка, символ)
|
||||
}
|
||||
}
|
||||
|
||||
вернуть строка
|
||||
}
|
||||
|
||||
фн читать буль буль(стр := Строка, ошибка := Строка): Лог {
|
||||
пусть истинаСтр = "true"
|
||||
пусть ложьСтр = "false"
|
||||
|
||||
если строки.есть префикс(стр, истинаСтр) {
|
||||
стр := строки.извлечь(стр, длина(истинаСтр(:Строка8)), длина(стр(:Строка8)) - длина(истинаСтр(:Строка8)))
|
||||
вернуть истина
|
||||
} иначе если строки.есть префикс(стр, ложьСтр) {
|
||||
стр := строки.извлечь(стр, длина(ложьСтр(:Строка8)), длина(стр(:Строка8)) - длина(ложьСтр(:Строка8)))
|
||||
вернуть ложь
|
||||
} иначе {
|
||||
пусть символ = посмотреть но не трогать(стр, ошибка)
|
||||
если ошибка # "" { вернуть ложь }
|
||||
|
||||
ошибка := спринтф.ф("ожидалось 'true' или 'false', а пришёл '$символ'", символ)
|
||||
вернуть ложь
|
||||
}
|
||||
}
|
||||
|
||||
фн токенизировать(стр: Строка, ошибка := Строка): ДжесонТокены {
|
||||
пусть токены = ДжесонТокены[]
|
||||
пусть сколько открыто := 0
|
||||
|
||||
пока истина {
|
||||
если длина(стр) = 0 & сколько открыто = 0 {
|
||||
прервать
|
||||
}
|
||||
|
||||
пусть символ = посмотреть но не трогать(стр, ошибка)
|
||||
если ошибка # "" { вернуть ДжесонТокены[] }
|
||||
|
||||
пусть является цифрой := ложь
|
||||
цикл [номер]цифра среди цифры {
|
||||
если символ = цифра {
|
||||
является цифрой := истина
|
||||
прервать
|
||||
}
|
||||
}
|
||||
|
||||
если символ = " " | символ = "\n" | символ = "\r" | символ = "\t" {
|
||||
стр := строки.извлечь(стр, 1, длина(стр(:Строка8)) - 1)
|
||||
} иначе если символ = "{" {
|
||||
стр := строки.извлечь(стр, 1, длина(стр(:Строка8)) - 1)
|
||||
|
||||
токены.добавить(ТокенФигурнаяСкобка{закрывающая: ложь})
|
||||
сколько открыто := сколько открыто + 1
|
||||
} иначе если символ = "}" {
|
||||
стр := строки.извлечь(стр, 1, длина(стр(:Строка8)) - 1)
|
||||
|
||||
токены.добавить(ТокенФигурнаяСкобка{закрывающая: истина})
|
||||
сколько открыто := сколько открыто - 1
|
||||
} иначе если символ = "[" {
|
||||
стр := строки.извлечь(стр, 1, длина(стр(:Строка8)) - 1)
|
||||
|
||||
токены.добавить(ТокенКвадратнаяСкобка{закрывающая: ложь})
|
||||
} иначе если символ = "]" {
|
||||
стр := строки.извлечь(стр, 1, длина(стр(:Строка8)) - 1)
|
||||
|
||||
токены.добавить(ТокенКвадратнаяСкобка{закрывающая: истина})
|
||||
} иначе если символ = "," {
|
||||
стр := строки.извлечь(стр, 1, длина(стр(:Строка8)) - 1)
|
||||
|
||||
токены.добавить(ТокенЗапятая{})
|
||||
} иначе если символ = ":" {
|
||||
стр := строки.извлечь(стр, 1, длина(стр(:Строка8)) - 1)
|
||||
|
||||
токены.добавить(ТокенДвоеточие{})
|
||||
} иначе если является цифрой {
|
||||
пусть число = читать число(стр, ошибка)
|
||||
если ошибка # "" { вернуть ДжесонТокены[] }
|
||||
|
||||
токены.добавить(ТокенЧисло{значение: число})
|
||||
} иначе если символ = "\"" {
|
||||
пусть строка = читать строку(стр, ошибка)
|
||||
если ошибка # "" { вернуть ДжесонТокены[] }
|
||||
|
||||
токены.добавить(ТокенСтрока{значение: строка})
|
||||
} иначе если символ = "t" | символ = "f" {
|
||||
пусть буль = читать буль буль(стр, ошибка)
|
||||
если ошибка # "" { вернуть ДжесонТокены[] }
|
||||
|
||||
токены.добавить(ТокенБульБуль{значение: буль})
|
||||
} иначе {
|
||||
ошибка := спринтф.ф("внезапный символ '$стр'", символ)
|
||||
вернуть ДжесонТокены[]
|
||||
}
|
||||
}
|
||||
|
||||
вернуть токены
|
||||
}
|
||||
259
исх/форматы/джесон/парсер.tri
Normal file
259
исх/форматы/джесон/парсер.tri
Normal file
@@ -0,0 +1,259 @@
|
||||
модуль джесон
|
||||
|
||||
импорт "исх/строка"
|
||||
импорт "исх/спринтф"
|
||||
|
||||
фн парсить массив(токены: ДжесонТокены, старт: Цел64, использовано токенов := Цел64, ошибка := Строка): ДжесонМногоЗначений {
|
||||
пусть массив = ДжесонМногоЗначений{значения: ДжесонЗначения[]}
|
||||
пусть текущий индекс := старт
|
||||
|
||||
если текущий индекс >= длина(токены) {
|
||||
ошибка := "неожиданный конец, ожидалась ["
|
||||
вернуть ДжесонМногоЗначений{}
|
||||
}
|
||||
|
||||
пусть токен := токены[текущий индекс]
|
||||
|
||||
выбор пусть т: тип токен {
|
||||
когда ТокенКвадратнаяСкобка:
|
||||
если т.закрывающая {
|
||||
ошибка := спринтф.ф("ожидалась [, а получен $стр", токен.в строку())
|
||||
вернуть ДжесонМногоЗначений{}
|
||||
} иначе {
|
||||
текущий индекс++
|
||||
}
|
||||
другое
|
||||
ошибка := спринтф.ф("ожидалась [, а получен $стр", токен.в строку())
|
||||
вернуть ДжесонМногоЗначений{}
|
||||
}
|
||||
|
||||
пока текущий индекс < длина(токены) {
|
||||
токен := токены[текущий индекс]
|
||||
|
||||
пусть значение: ДжесонЗначение := ДжесонЗначение{}
|
||||
|
||||
выбор пусть т: тип токен {
|
||||
когда ТокенСтрока:
|
||||
значение := ДжесонСтрока{значение: т.значение}
|
||||
текущий индекс++
|
||||
когда ТокенЧисло:
|
||||
значение := ДжесонЧисло{значение: т.значение}
|
||||
текущий индекс++
|
||||
когда ТокенБульБуль:
|
||||
значение := ДжесонЛог{значение: т.значение}
|
||||
текущий индекс++
|
||||
когда ТокенКвадратнаяСкобка:
|
||||
если т.закрывающая {
|
||||
текущий индекс++
|
||||
использовано токенов := текущий индекс - старт
|
||||
вернуть массив
|
||||
} иначе {
|
||||
ошибка := спринтф.ф("ожидалась значение или ], а получен $стр", токен.в строку())
|
||||
вернуть ДжесонМногоЗначений{}
|
||||
}
|
||||
когда ТокенФигурнаяСкобка:
|
||||
если ~т.закрывающая {
|
||||
пусть использовано := 0
|
||||
значение := парсить объект(токены, текущий индекс, использовано, ошибка)
|
||||
|
||||
если ошибка # "" { вернуть ДжесонМногоЗначений{} }
|
||||
|
||||
текущий индекс := текущий индекс + использовано
|
||||
}
|
||||
другое
|
||||
ошибка := спринтф.ф("неожиданное значение: $стр", токен.в строку())
|
||||
вернуть ДжесонМногоЗначений{}
|
||||
}
|
||||
|
||||
массив.значения.добавить(значение)
|
||||
|
||||
если текущий индекс >= длина(токены) {
|
||||
ошибка := "неожиданный конец, ожидался , или ]"
|
||||
вернуть ДжесонМногоЗначений{}
|
||||
}
|
||||
|
||||
токен := токены[текущий индекс]
|
||||
|
||||
выбор пусть т: тип токен {
|
||||
когда ТокенКвадратнаяСкобка:
|
||||
если т.закрывающая {
|
||||
текущий индекс++
|
||||
использовано токенов := текущий индекс - старт
|
||||
вернуть массив
|
||||
} иначе {
|
||||
ошибка := спринтф.ф("ожидалась , или ], а получен $стр", токен.в строку())
|
||||
вернуть ДжесонМногоЗначений{}
|
||||
}
|
||||
когда ТокенЗапятая:
|
||||
текущий индекс++
|
||||
другое
|
||||
ошибка := спринтф.ф("ожидалась , или ], а получен $стр", токен.в строку())
|
||||
вернуть ДжесонМногоЗначений{}
|
||||
}
|
||||
}
|
||||
|
||||
ошибка := "неожиданный конец во время парсинга массива"
|
||||
вернуть ДжесонМногоЗначений{}
|
||||
}
|
||||
|
||||
фн парсить объект(токены: ДжесонТокены, старт: Цел64, использовано токенов := Цел64, ошибка := Строка): ДжесонОбъект {
|
||||
пусть объект = ДжесонОбъект{}
|
||||
пусть текущий индекс := старт
|
||||
|
||||
если текущий индекс >= длина(токены) {
|
||||
ошибка := "неожиданный конец, ожидалось {"
|
||||
вернуть ДжесонОбъект{}
|
||||
}
|
||||
|
||||
пусть токен := токены[текущий индекс]
|
||||
|
||||
выбор пусть т: тип токен {
|
||||
когда ТокенФигурнаяСкобка:
|
||||
если т.закрывающая {
|
||||
ошибка := спринтф.ф("ожидалась {, а получен $стр", токен.в строку())
|
||||
вернуть ДжесонОбъект{}
|
||||
} иначе {
|
||||
текущий индекс++
|
||||
}
|
||||
другое
|
||||
ошибка := спринтф.ф("ожидалась {, а получен $стр", токен.в строку())
|
||||
вернуть ДжесонОбъект{}
|
||||
}
|
||||
|
||||
пока текущий индекс < длина(токены) {
|
||||
токен := токены[текущий индекс]
|
||||
пусть ключ := ""
|
||||
|
||||
выбор пусть т: тип токен {
|
||||
когда ТокенСтрока:
|
||||
ключ := т.значение
|
||||
текущий индекс++
|
||||
когда ТокенФигурнаяСкобка:
|
||||
если т.закрывающая {
|
||||
текущий индекс++
|
||||
использовано токенов := текущий индекс - старт
|
||||
вернуть объект
|
||||
} иначе {
|
||||
ошибка := спринтф.ф("ожидалась строка (ключ), а получен $стр", токен.в строку())
|
||||
вернуть ДжесонОбъект{}
|
||||
}
|
||||
другое
|
||||
ошибка := спринтф.ф("ожидалась строка (ключ), а получен $стр", токен.в строку())
|
||||
вернуть ДжесонОбъект{}
|
||||
}
|
||||
|
||||
если текущий индекс >= длина(токены) {
|
||||
ошибка := "неожиданный конец, ожидалось :"
|
||||
вернуть ДжесонОбъект{}
|
||||
}
|
||||
|
||||
токен := токены[текущий индекс]
|
||||
выбор пусть т: тип токен {
|
||||
когда ТокенДвоеточие:
|
||||
текущий индекс++
|
||||
другое
|
||||
ошибка := спринтф.ф("ожидался :, а получен $стр", токен.в строку())
|
||||
вернуть ДжесонОбъект{}
|
||||
}
|
||||
|
||||
если текущий индекс >= длина(токены) {
|
||||
ошибка := "неожиданный конец, ожидалось значение"
|
||||
вернуть ДжесонОбъект{}
|
||||
}
|
||||
|
||||
токен := токены[текущий индекс]
|
||||
|
||||
пусть значение: ДжесонЗначение := ДжесонЗначение{}
|
||||
выбор пусть т: тип токен {
|
||||
когда ТокенСтрока:
|
||||
значение := ДжесонСтрока{значение: т.значение}
|
||||
текущий индекс++
|
||||
когда ТокенЧисло:
|
||||
значение := ДжесонЧисло{значение: т.значение}
|
||||
текущий индекс++
|
||||
когда ТокенБульБуль:
|
||||
значение := ДжесонЛог{значение: т.значение}
|
||||
текущий индекс++
|
||||
когда ТокенФигурнаяСкобка:
|
||||
если ~т.закрывающая {
|
||||
пусть использовано := 0
|
||||
значение := парсить объект(токены, текущий индекс, использовано, ошибка)
|
||||
|
||||
если ошибка # "" { вернуть ДжесонОбъект{} }
|
||||
|
||||
текущий индекс := текущий индекс + использовано
|
||||
} иначе {
|
||||
ошибка := спринтф.ф("ожидалось значение, а получен $стр", токен.в строку())
|
||||
вернуть ДжесонОбъект{}
|
||||
}
|
||||
когда ТокенКвадратнаяСкобка:
|
||||
если т.закрывающая {
|
||||
ошибка := спринтф.ф("ожидалось значение, а получен $стр", токен.в строку())
|
||||
вернуть ДжесонОбъект{}
|
||||
} иначе {
|
||||
пусть использовано := 0
|
||||
значение := парсить массив(токены, текущий индекс, использовано, ошибка)
|
||||
|
||||
если ошибка # "" { вернуть ДжесонОбъект{} }
|
||||
текущий индекс := текущий индекс + использовано
|
||||
}
|
||||
другое
|
||||
ошибка := спринтф.ф("неожиданное значение: $стр", токен.в строку())
|
||||
вернуть ДжесонОбъект{}
|
||||
}
|
||||
|
||||
объект.значения.добавить(ДжесонКлючЗначение{ключ: ключ, значение: значение})
|
||||
|
||||
если текущий индекс >= длина(токены) {
|
||||
ошибка := "неожиданный конец, ожидался , или }"
|
||||
вернуть ДжесонОбъект{}
|
||||
}
|
||||
|
||||
токен := токены[текущий индекс]
|
||||
|
||||
выбор пусть т: тип токен {
|
||||
когда ТокенЗапятая:
|
||||
текущий индекс++
|
||||
когда ТокенФигурнаяСкобка:
|
||||
если т.закрывающая {
|
||||
текущий индекс++
|
||||
использовано токенов := текущий индекс - старт
|
||||
вернуть объект
|
||||
} иначе {
|
||||
ошибка := спринтф.ф("ожидалась , или }, а получен $стр", токен.в строку())
|
||||
вернуть ДжесонОбъект{}
|
||||
}
|
||||
другое
|
||||
ошибка := спринтф.ф("ожидалась , или }, а получен $стр", токен.в строку())
|
||||
вернуть ДжесонОбъект{}
|
||||
}
|
||||
}
|
||||
|
||||
ошибка := "неожиданный конец во время парсинга объекта"
|
||||
вернуть ДжесонОбъект{}
|
||||
}
|
||||
|
||||
фн парсить токены(токены: ДжесонТокены, ошибка := Строка): ДжесонОбъект {
|
||||
пусть использовано токенов := 0
|
||||
вернуть парсить объект(токены, 0, использовано токенов, ошибка)
|
||||
}
|
||||
|
||||
фн парсить*(строка: Строка, ошибка := Строка): ДжесонОбъект {
|
||||
пусть токены = токенизировать(строка, ошибка)
|
||||
|
||||
если ошибка # "" {
|
||||
вернуть ДжесонОбъект{}
|
||||
}
|
||||
|
||||
пусть объект = парсить токены(токены, ошибка)
|
||||
|
||||
если ошибка # "" {
|
||||
вернуть ДжесонОбъект{}
|
||||
}
|
||||
|
||||
вернуть объект
|
||||
}
|
||||
|
||||
фн сериализовать*(объект: ДжесонОбъект): Строка {
|
||||
вернуть массив токенов в строку(объект.в токены())
|
||||
}
|
||||
205
исх/форматы/джесон/типы.tri
Normal file
205
исх/форматы/джесон/типы.tri
Normal file
@@ -0,0 +1,205 @@
|
||||
модуль джесон
|
||||
|
||||
импорт "исх/строка"
|
||||
импорт "исх/спринтф"
|
||||
|
||||
тип ДжесонЗначение* = класс {
|
||||
|
||||
}
|
||||
|
||||
фн (значение: ДжесонЗначение) в строку*(): Строка {
|
||||
вернуть "пустое значение"
|
||||
}
|
||||
|
||||
фн (значение: ДжесонЗначение) в токены(): ДжесонТокены {
|
||||
авария("попытка преобразовать в токены базовое значение")
|
||||
}
|
||||
|
||||
фн (значение: ДжесонЗначение) пустое*(): Лог {
|
||||
вернуть истина
|
||||
}
|
||||
|
||||
фн (значение: ДжесонЗначение) строка*(): мб Строка {
|
||||
вернуть пусто
|
||||
}
|
||||
|
||||
фн (значение: ДжесонЗначение) число*(): мб ДжесонЧисло {
|
||||
вернуть пусто
|
||||
}
|
||||
|
||||
тип ДжесонЗначения* = []ДжесонЗначение
|
||||
|
||||
тип ДжесонСтрока* = класс(ДжесонЗначение) {
|
||||
значение*: Строка := ""
|
||||
}
|
||||
|
||||
фн (строка: ДжесонСтрока) в строку*(): Строка {
|
||||
вернуть спринтф.ф("\"$стр\"", строка.значение)
|
||||
}
|
||||
|
||||
фн (строка: ДжесонСтрока) в токены(): ДжесонТокены {
|
||||
вернуть ДжесонТокены[ТокенСтрока{значение: строка.значение}]
|
||||
}
|
||||
|
||||
фн (строка: ДжесонСтрока) пустое*(): Лог {
|
||||
вернуть ложь
|
||||
}
|
||||
|
||||
фн (строка: ДжесонСтрока) строка*(): мб Строка {
|
||||
вернуть строка.значение
|
||||
}
|
||||
|
||||
тип ДжесонЧисло* = класс(ДжесонЗначение) {
|
||||
значение*: Цел64 := 0
|
||||
}
|
||||
|
||||
фн (число: ДжесонЧисло) в строку*(): Строка {
|
||||
вернуть спринтф.ф("$цел", число.значение)
|
||||
}
|
||||
|
||||
фн (число: ДжесонЧисло) в токены(): ДжесонТокены {
|
||||
вернуть ДжесонТокены[ТокенЧисло{значение: число.значение}]
|
||||
}
|
||||
|
||||
фн (число: ДжесонЧисло) пустое*(): Лог {
|
||||
вернуть ложь
|
||||
}
|
||||
|
||||
фн (число: ДжесонЧисло) число*(): мб ДжесонЧисло {
|
||||
вернуть число
|
||||
}
|
||||
|
||||
тип ДжесонЛог* = класс(ДжесонЗначение) {
|
||||
значение*: Лог := ложь
|
||||
}
|
||||
|
||||
фн (лог: ДжесонЛог) в строку*(): Строка {
|
||||
если лог.значение {
|
||||
вернуть "истина"
|
||||
}
|
||||
|
||||
вернуть "ложб"
|
||||
}
|
||||
|
||||
фн (лог: ДжесонЛог) в токены(): ДжесонТокены {
|
||||
вернуть ДжесонТокены[ТокенБульБуль{значение: лог.значение}]
|
||||
}
|
||||
|
||||
фн (лог: ДжесонЛог) пустое*(): Лог {
|
||||
вернуть ложь
|
||||
}
|
||||
|
||||
тип ДжесонМногоЗначений* = класс(ДжесонЗначение) {
|
||||
значения*: ДжесонЗначения = ДжесонЗначения[]
|
||||
}
|
||||
|
||||
фн (значения: ДжесонМногоЗначений) в строку*(): Строка {
|
||||
пусть выходная строка := ""
|
||||
|
||||
цикл [номер]значение среди значения.значения {
|
||||
если номер > 0 {
|
||||
выходная строка := спринтф.ф("$стр, ", выходная строка)
|
||||
}
|
||||
|
||||
выходная строка := строка.собрать(выходная строка, значение.в строку())
|
||||
}
|
||||
|
||||
вернуть спринтф.ф("[$стр]", выходная строка)
|
||||
}
|
||||
|
||||
фн (значения: ДжесонМногоЗначений) в токены(): ДжесонТокены {
|
||||
пусть токены = ДжесонТокены[ТокенКвадратнаяСкобка{закрывающая: ложь}]
|
||||
|
||||
цикл [номер]значение среди значения.значения {
|
||||
если номер > 0 {
|
||||
токены.добавить(ТокенЗапятая{})
|
||||
}
|
||||
|
||||
токены.добавить(значение.в токены()...)
|
||||
}
|
||||
|
||||
токены.добавить(ТокенКвадратнаяСкобка{закрывающая: истина})
|
||||
|
||||
вернуть токены
|
||||
}
|
||||
|
||||
фн (значения: ДжесонМногоЗначений) пустое*(): Лог {
|
||||
вернуть длина(значения.значения) = 0
|
||||
}
|
||||
|
||||
тип ДжесонОбъект* = класс(ДжесонЗначение) {
|
||||
значения*: ДжесонКлючЗначения := ДжесонКлючЗначения[]
|
||||
}
|
||||
|
||||
фн (объект: ДжесонОбъект) в строку*(): Строка {
|
||||
пусть выходная строка := ""
|
||||
|
||||
цикл [номер]значение среди объект.значения {
|
||||
если номер > 0 {
|
||||
выходная строка := спринтф.ф("$стр,\n", выходная строка)
|
||||
} иначе {
|
||||
выходная строка := спринтф.ф("\n$стр", выходная строка)
|
||||
}
|
||||
|
||||
выходная строка := строка.собрать(выходная строка, спринтф.ф("\"$стр\": $стр", значение.ключ, значение.значение.в строку()))
|
||||
}
|
||||
|
||||
вернуть спринтф.ф("{$стр\n}", выходная строка)
|
||||
}
|
||||
|
||||
фн (объект: ДжесонОбъект) в токены(): ДжесонТокены {
|
||||
пусть токены = ДжесонТокены[ТокенФигурнаяСкобка{закрывающая: ложь}]
|
||||
|
||||
цикл [номер]значение среди объект.значения {
|
||||
если номер > 0 {
|
||||
токены.добавить(ТокенЗапятая{})
|
||||
}
|
||||
|
||||
токены.добавить(ТокенСтрока{значение: значение.ключ})
|
||||
токены.добавить(ТокенДвоеточие{})
|
||||
токены.добавить(значение.значение.в токены()...)
|
||||
}
|
||||
|
||||
токены.добавить(ТокенФигурнаяСкобка{закрывающая: истина})
|
||||
|
||||
вернуть токены
|
||||
}
|
||||
|
||||
фн (объект: ДжесонОбъект) пустое*(): Лог {
|
||||
вернуть ложь
|
||||
}
|
||||
|
||||
фн (объект: ДжесонОбъект) получить*(ключ: Строка): ДжесонЗначение {
|
||||
пусть количество = длина(объект.значения)
|
||||
пусть ай := количество - 1
|
||||
|
||||
пока ай >= 0 {
|
||||
пусть значение = объект.значения[ай]
|
||||
|
||||
если значение.ключ = ключ {
|
||||
вернуть значение.значение
|
||||
}
|
||||
|
||||
ай := ай - 1
|
||||
}
|
||||
|
||||
вернуть ДжесонЗначение{}
|
||||
}
|
||||
|
||||
фн (объект: ДжесонОбъект) вставить*(ключ: Строка, новое значение: ДжесонЗначение) {
|
||||
цикл [номер]значение среди объект.значения {
|
||||
если значение.ключ = ключ {
|
||||
объект.значения[номер].значение := новое значение
|
||||
вернуть
|
||||
}
|
||||
}
|
||||
|
||||
объект.значения.добавить(ДжесонКлючЗначение{ключ: ключ, значение: новое значение})
|
||||
}
|
||||
|
||||
тип ДжесонКлючЗначение* = класс {
|
||||
ключ*: Строка := ""
|
||||
значение*: ДжесонЗначение := позже
|
||||
}
|
||||
|
||||
тип ДжесонКлючЗначения* = []ДжесонКлючЗначение
|
||||
Reference in New Issue
Block a user