geochan/src/babillard.ml

576 lines
18 KiB
OCaml
Raw Normal View History

2021-12-29 21:07:17 +01:00
open Db
2022-02-02 19:16:53 +01:00
include Bindings
2021-12-29 21:07:17 +01:00
2022-03-17 01:05:25 +01:00
type moderation_action =
| Ignore
| Delete
| Banish
let moderation_action_to_string = function
| Ignore -> "ignore"
| Delete -> "delete"
| Banish -> "banish"
let moderation_action_from_string = function
| "ignore" -> Some Ignore
| "delete" -> Some Delete
| "banish" -> Some Banish
| _ -> None
2022-01-29 09:23:57 +01:00
type thread_data =
{ subject : string
2022-01-29 09:23:57 +01:00
; lng : float
; lat : float
}
type post =
{ id : string
; parent_id : string
2022-02-23 14:30:06 +01:00
; date : float
2022-03-08 21:20:01 +01:00
; user_id : string
; nick : string
; comment : string
2022-02-18 19:40:19 +01:00
; image_info : (string * string) option
; tags : string list
; replies : string list
; citations : string list
}
2022-03-16 03:06:59 +01:00
type image =
{ name : string
; alt : string
; content : string
2022-03-15 00:12:36 +01:00
; thumbnail : string
2022-03-16 03:06:59 +01:00
}
type t =
| Op of thread_data * post
| Post of post
2021-12-29 21:07:17 +01:00
module Q = struct
let create_post_user_table =
Caqti_request.exec Caqti_type.unit
2022-03-08 21:20:01 +01:00
"CREATE TABLE IF NOT EXISTS post_user (post_id TEXT, user_id TEXT, \
PRIMARY KEY(post_id), FOREIGN KEY(user_id) REFERENCES user(user_id) ON \
DELETE CASCADE);"
2021-12-29 21:07:17 +01:00
(* one row for each thread, with thread's data *)
let create_thread_info_table =
2021-12-29 21:07:17 +01:00
Caqti_request.exec Caqti_type.unit
"CREATE TABLE IF NOT EXISTS thread_info (thread_id TEXT, subject TEXT, \
lat FLOAT, lng FLOAT, FOREIGN KEY(thread_id) REFERENCES \
2022-02-21 10:17:43 +01:00
post_user(post_id) ON DELETE CASCADE);"
(* map thread and reply to the thread *)
let create_thread_post_table =
Caqti_request.exec Caqti_type.unit
2022-02-22 00:01:35 +01:00
"CREATE TABLE IF NOT EXISTS thread_post (thread_id TEXT, post_id TEXT, \
FOREIGN KEY(thread_id) REFERENCES post_user(post_id) ON DELETE CASCADE, \
FOREIGN KEY(post_id) REFERENCES post_user(post_id) ON DELETE CASCADE);"
2021-12-29 21:07:17 +01:00
let create_post_replies_table =
Caqti_request.exec Caqti_type.unit
"CREATE TABLE IF NOT EXISTS post_replies (post_id TEXT, reply_id TEXT, \
2022-02-22 00:01:35 +01:00
FOREIGN KEY(post_id) REFERENCES post_user(post_id) ON DELETE CASCADE, \
FOREIGN KEY(reply_id) REFERENCES post_user(post_id) ON DELETE CASCADE);"
2021-12-29 21:07:17 +01:00
let create_post_citations_table =
Caqti_request.exec Caqti_type.unit
"CREATE TABLE IF NOT EXISTS post_citations (post_id TEXT, cited_id TEXT, \
2022-02-22 00:01:35 +01:00
FOREIGN KEY(post_id) REFERENCES post_user(post_id) ON DELETE CASCADE, \
FOREIGN KEY(cited_id) REFERENCES post_user(post_id) ON DELETE CASCADE);"
2021-12-29 21:07:17 +01:00
let create_post_date_table =
Caqti_request.exec Caqti_type.unit
2022-02-23 14:30:06 +01:00
"CREATE TABLE IF NOT EXISTS post_date (post_id TEXT, date FLOAT, FOREIGN \
2022-02-21 10:17:43 +01:00
KEY(post_id) REFERENCES post_user(post_id) ON DELETE CASCADE);"
2021-12-29 21:07:17 +01:00
let create_post_comment_table =
Caqti_request.exec Caqti_type.unit
"CREATE TABLE IF NOT EXISTS post_comment (post_id TEXT, comment TEXT, \
2022-02-21 10:17:43 +01:00
FOREIGN KEY(post_id) REFERENCES post_user(post_id) ON DELETE CASCADE);"
2021-12-29 21:07:17 +01:00
2022-02-18 19:40:19 +01:00
let create_image_info_table =
2021-12-29 21:07:17 +01:00
Caqti_request.exec Caqti_type.unit
2022-02-18 19:40:19 +01:00
"CREATE TABLE IF NOT EXISTS image_info (post_id TEXT, image_name TEXT, \
2022-02-21 10:17:43 +01:00
image_alt TEXT, FOREIGN KEY(post_id) REFERENCES post_user(post_id) ON \
DELETE CASCADE);"
2022-02-18 19:40:19 +01:00
let create_image_content_table =
Caqti_request.exec Caqti_type.unit
2022-03-15 00:12:36 +01:00
"CREATE TABLE IF NOT EXISTS image_content (post_id TEXT, content TEXT, \
FOREIGN KEY(post_id) REFERENCES post_user(post_id) ON DELETE CASCADE);"
let create_image_thumbnail_table =
Caqti_request.exec Caqti_type.unit
"CREATE TABLE IF NOT EXISTS image_thumbnail (post_id TEXT, content TEXT, \
FOREIGN KEY(post_id) REFERENCES post_user(post_id) ON DELETE CASCADE);"
2021-12-29 21:07:17 +01:00
let create_post_tags_table =
Caqti_request.exec Caqti_type.unit
"CREATE TABLE IF NOT EXISTS post_tags (post_id TEXT, tag TEXT, FOREIGN \
2022-02-21 10:17:43 +01:00
KEY(post_id) REFERENCES post_user(post_id) ON DELETE CASCADE);"
2021-12-29 21:07:17 +01:00
2022-02-22 07:10:52 +01:00
let create_report_table =
Caqti_request.exec Caqti_type.unit
2022-03-08 21:20:01 +01:00
"CREATE TABLE IF NOT EXISTS report (user_id TEXT, reason TEXT, date \
2022-02-23 14:30:06 +01:00
FLOAT,post_id TEXT, FOREIGN KEY(post_id) REFERENCES post_user(post_id) \
2022-03-08 21:20:01 +01:00
ON DELETE CASCADE, FOREIGN KEY(user_id) REFERENCES user(user_id) ON \
DELETE CASCADE);"
2022-02-22 07:10:52 +01:00
2022-02-23 22:39:48 +01:00
let upload_report =
2022-02-22 07:10:52 +01:00
Caqti_request.exec
2022-02-23 14:30:06 +01:00
Caqti_type.(tup4 string string float string)
2022-02-22 07:10:52 +01:00
"INSERT INTO report VALUES (?,?,?,?);"
2022-02-23 22:39:48 +01:00
let ignore_report =
Caqti_request.exec Caqti_type.string "DELETE FROM report WHERE post_id=?;"
let get_reports =
Caqti_request.collect Caqti_type.unit
Caqti_type.(tup4 string string float string)
"SELECT * FROM report;"
2021-12-29 21:07:17 +01:00
let upload_post_id =
Caqti_request.exec
Caqti_type.(tup2 string string)
"INSERT INTO post_user VALUES (?,?);"
let upload_thread_info =
2021-12-29 21:07:17 +01:00
Caqti_request.exec
Caqti_type.(tup4 string string float float)
"INSERT INTO thread_info VALUES (?,?,?,?);"
let upload_thread_post =
Caqti_request.exec
Caqti_type.(tup2 string string)
"INSERT INTO thread_post VALUES (?,?);"
2021-12-29 21:07:17 +01:00
2022-02-18 19:40:19 +01:00
let upload_image_info =
2021-12-29 21:07:17 +01:00
Caqti_request.exec
2022-02-18 19:40:19 +01:00
Caqti_type.(tup3 string string string)
"INSERT INTO image_info VALUES (?,?,?);"
let upload_image_content =
Caqti_request.exec
Caqti_type.(tup2 string string)
"INSERT INTO image_content VALUES (?,?);"
2021-12-29 21:07:17 +01:00
2022-03-15 00:12:36 +01:00
let upload_image_thumbnail =
Caqti_request.exec
Caqti_type.(tup2 string string)
"INSERT INTO image_thumbnail VALUES (?,?);"
2021-12-29 21:07:17 +01:00
let upload_post_reply =
Caqti_request.exec
Caqti_type.(tup2 string string)
"INSERT INTO post_replies VALUES (?,?);"
let upload_post_comment =
Caqti_request.exec
Caqti_type.(tup2 string string)
"INSERT INTO post_comment VALUES (?,?);"
let upload_post_tag =
Caqti_request.exec
Caqti_type.(tup2 string string)
"INSERT INTO post_tags VALUES (?,?);"
let upload_post_date =
Caqti_request.exec
2022-02-23 14:30:06 +01:00
Caqti_type.(tup2 string float)
2021-12-29 21:07:17 +01:00
"INSERT INTO post_date VALUES (?,?);"
2022-03-08 21:20:01 +01:00
let get_post_user_id =
2021-12-29 21:07:17 +01:00
Caqti_request.find Caqti_type.string Caqti_type.string
2022-03-08 21:20:01 +01:00
"SELECT user_id FROM post_user WHERE post_id=?;"
2021-12-29 21:07:17 +01:00
let get_post_comment =
Caqti_request.find Caqti_type.string Caqti_type.string
"SELECT comment FROM post_comment WHERE post_id=?;"
let get_post_image_content =
Caqti_request.find_opt Caqti_type.string Caqti_type.string
2022-03-15 00:12:36 +01:00
"SELECT content FROM image_content WHERE post_id=?;"
let get_post_image_thumbnail =
Caqti_request.find_opt Caqti_type.string Caqti_type.string
"SELECT content FROM image_thumbnail WHERE post_id=?;"
2021-12-29 21:07:17 +01:00
2022-01-25 14:07:28 +01:00
let get_post_image_info =
Caqti_request.find_opt Caqti_type.string
Caqti_type.(tup2 string string)
2022-02-18 19:40:19 +01:00
"SELECT image_name,image_alt FROM image_info WHERE post_id=?;"
2021-12-29 21:07:17 +01:00
let get_post_tags =
Caqti_request.collect Caqti_type.string Caqti_type.string
"SELECT tag FROM post_tags WHERE post_id=?;"
let get_post_date =
2022-02-23 14:30:06 +01:00
Caqti_request.find Caqti_type.string Caqti_type.float
2021-12-29 21:07:17 +01:00
"SELECT date FROM post_date WHERE post_id=?;"
let get_post_citations =
Caqti_request.collect Caqti_type.string Caqti_type.string
"SELECT post_id FROM post_citations WHERE post_id=?;"
2021-12-29 21:07:17 +01:00
let get_post_replies =
Caqti_request.collect Caqti_type.string Caqti_type.string
"SELECT reply_id FROM post_replies WHERE post_id=?;"
let get_thread_posts =
Caqti_request.collect Caqti_type.string Caqti_type.string
"SELECT post_id FROM thread_post WHERE thread_id=?;"
2021-12-29 21:07:17 +01:00
2022-01-14 14:05:09 +01:00
let count_thread_posts =
Caqti_request.find Caqti_type.string Caqti_type.int
"SELECT COUNT(post_id) FROM thread_post WHERE thread_id=?;"
2022-01-14 14:05:09 +01:00
let get_is_thread =
2022-02-18 01:37:25 +01:00
Caqti_request.find Caqti_type.string Caqti_type.string
"SELECT thread_id FROM thread_info WHERE thread_id=? LIMIT 1;"
let get_is_post =
Caqti_request.find Caqti_type.string Caqti_type.string
"SELECT post_id FROM post_user WHERE post_id=? LIMIT 1;"
let get_post_thread =
Caqti_request.find Caqti_type.string Caqti_type.string
"SELECT thread_id FROM thread_post WHERE post_id=? LIMIT 1;"
2021-12-29 21:07:17 +01:00
let get_thread_info =
Caqti_request.find Caqti_type.string
Caqti_type.(tup3 string float float)
"SELECT subject,lat,lng FROM thread_info WHERE thread_id=?;"
2021-12-29 21:07:17 +01:00
let get_threads =
Caqti_request.collect Caqti_type.unit Caqti_type.string
"SELECT thread_id FROM thread_info;"
2022-02-21 09:46:27 +01:00
let delete_post =
Caqti_request.exec Caqti_type.string
"DELETE FROM post_user WHERE post_id=?;"
2021-12-29 21:07:17 +01:00
end
let () =
let tables =
2022-02-28 18:35:16 +01:00
[| Q.create_post_user_table
; Q.create_thread_info_table
; Q.create_thread_post_table
; Q.create_post_replies_table
; Q.create_post_citations_table
; Q.create_post_date_table
; Q.create_post_comment_table
; Q.create_image_info_table
; Q.create_image_content_table
2022-03-15 00:12:36 +01:00
; Q.create_image_thumbnail_table
2022-02-28 18:35:16 +01:00
; Q.create_post_tags_table
; Q.create_report_table
|]
2021-12-29 21:07:17 +01:00
in
if
2022-02-28 18:35:16 +01:00
Array.exists Result.is_error
(Array.map (fun query -> Db.exec query ()) tables)
2022-03-06 19:23:52 +01:00
then Dream.error (fun log -> log "can't create babillard's tables")
2021-12-29 21:07:17 +01:00
2022-03-16 03:06:59 +01:00
let clean_image image =
let name, alt, content = image in
let name =
match name with
| Some name -> Dream.html_escape name
| None ->
(* make up random name if no name was given *)
Uuidm.to_string (Uuidm.v4_gen random_state ())
in
if not (is_valid_image content) then Error "invalid image"
else if String.length alt > 1000 then Error "Image description too long"
else Ok (name, alt, content)
2022-01-25 14:07:28 +01:00
2022-03-15 00:12:36 +01:00
let make_thumbnail content =
let open Bos in
(* jpp *)
let ( let* ) o f =
Result.fold ~ok:f ~error:(function `Msg s -> Result.error s) o
in
let* image_file = OS.File.tmp "%s" in
let* thumb_file = OS.File.tmp "%s_thumb" in
let* () = OS.File.write image_file content in
let cmd =
Cmd.(
v "convert" % "-define" % "jpeg:size=700x700" % p image_file
% "-auto-orient" % "-thumbnail" % "300x300>" % "-unsharp" % "0x.5"
% "-format" % "jpg" % p thumb_file)
in
let* () = OS.Cmd.run cmd in
let* thumbnail = OS.File.read thumb_file in
let* () = OS.File.delete image_file in
let* () = OS.File.delete thumb_file in
Ok thumbnail
2022-03-15 00:12:36 +01:00
(*TODO switch to markdown !*)
(* insert html into the comment, and keep tracks of citations :
-wraps lines starting with ">" with a <span class="quote">
-make raw posts uuid into links
(*TODO fix bad link if post is in other thread*)
-keeps tracks of every post cited in this comment
- add <br> at each line *)
2021-12-29 21:07:17 +01:00
let parse_comment comment =
2022-02-26 15:28:23 +01:00
let citations = ref [] in
let pp_word fmt w =
let trim_w = String.trim w in
(* '>' is '&gt;' after html_escape *)
2022-02-27 19:58:32 +01:00
if String.length trim_w >= 8 then
let sub_w = String.sub trim_w 8 (String.length trim_w - 8) in
2022-02-27 19:58:32 +01:00
if
String.starts_with ~prefix:{|&gt;&gt;|} trim_w
&& Option.is_some (Uuidm.of_string sub_w)
then begin
2022-02-26 15:28:23 +01:00
citations := sub_w :: !citations;
2022-02-27 19:58:32 +01:00
Format.fprintf fmt {|<a href="#%s">%s</a>|} sub_w w
end
2022-02-26 15:28:23 +01:00
else Format.pp_print_string fmt w
else Format.pp_print_string fmt w
in
2022-02-26 15:28:23 +01:00
let pp_line fmt l =
let trim_w = String.trim l in
(*insert quote*)
2022-02-26 15:28:23 +01:00
let words = String.split_on_char ' ' l in
if
String.starts_with ~prefix:{|&gt;|} trim_w
&& not (String.starts_with ~prefix:{|&gt;&gt;|} trim_w)
then
Format.fprintf fmt {|<span class="quote">%a</span>|}
(Format.pp_print_list ~pp_sep:Format.pp_print_space pp_word)
words
2022-02-27 19:58:32 +01:00
else Format.pp_print_list ~pp_sep:Format.pp_print_space pp_word fmt words
in
2022-01-14 21:04:52 +01:00
let comment = String.trim comment in
let lines = String.split_on_char '\n' comment in
(*insert <br>*)
let comment =
Format.asprintf "%a"
(Format.pp_print_list
2022-02-26 15:28:23 +01:00
~pp_sep:(fun fmt () -> Format.fprintf fmt "@\n<br>")
pp_line )
lines
in
(* remove duplicate cited_id *)
2022-02-26 15:28:23 +01:00
let citations = List.sort_uniq String.compare !citations in
(comment, citations)
2021-12-29 21:07:17 +01:00
2022-03-16 03:06:59 +01:00
let upload_post ~image post =
2022-01-29 09:23:57 +01:00
let thread_data, reply =
match post with
2022-01-29 09:23:57 +01:00
| Op (thread_data, reply) -> (Some thread_data, reply)
| Post reply -> (None, reply)
2021-12-29 21:07:17 +01:00
in
2022-03-08 21:20:01 +01:00
let { id; parent_id; date; user_id; comment; image_info; tags; citations; _ }
=
reply
2022-01-29 09:23:57 +01:00
in
2022-03-08 21:20:01 +01:00
let^ () = Db.exec Q.upload_post_id (id, user_id) in
let^ () = Db.exec Q.upload_post_comment (id, comment) in
let^ () = Db.exec Q.upload_post_date (id, date) in
let^ () = Db.exec Q.upload_thread_post (parent_id, id) in
2022-03-16 03:06:59 +01:00
let* () =
match image with
| None -> Ok ()
| Some image ->
assert (Option.is_some image_info);
let^ () = Db.exec Q.upload_image_info (id, image.name, image.alt) in
let^ () = Db.exec Q.upload_image_content (id, image.content) in
2022-03-15 00:12:36 +01:00
let^ () = Db.exec Q.upload_image_thumbnail (id, image.thumbnail) in
2022-03-16 03:06:59 +01:00
Ok ()
2021-12-29 21:07:17 +01:00
in
2022-02-22 00:01:35 +01:00
let^ _unit_list =
unwrap_list (fun tag -> Db.exec Q.upload_post_tag (id, tag)) tags
in
let^ _unit_list =
2022-02-21 07:22:07 +01:00
unwrap_list
(fun cited_id -> Db.exec Q.upload_post_reply (cited_id, id))
citations
in
2022-01-29 09:23:57 +01:00
match thread_data with
| None -> Ok id
| Some { subject; lng; lat } ->
let^ () = Db.exec Q.upload_thread_info (id, subject, lat, lng) in
Ok id
2021-12-29 21:07:17 +01:00
2022-03-16 03:06:59 +01:00
let build_reply ~comment ~image_info ~tag_list ?parent_id user_id =
2022-01-14 21:04:52 +01:00
let comment = Dream.html_escape comment in
2022-01-29 09:23:57 +01:00
let id = Uuidm.to_string (Uuidm.v4_gen random_state ()) in
(* parent_id is None if this reply is supposed to be a new thread *)
let parent_id = Option.value parent_id ~default:id in
2022-02-18 02:40:04 +01:00
if Option.is_none (Uuidm.of_string parent_id) then Error "invalid thread id"
else if String.length comment > 10000 then Error "invalid comment"
2022-03-16 03:06:59 +01:00
else if List.length tag_list > 30 then Error "too much tags"
else if List.exists (fun tag -> String.length tag > 100) tag_list then
Error "tag too long"
else
2022-03-16 03:06:59 +01:00
let tag_list =
List.map String.lowercase_ascii
@@ List.sort_uniq String.compare
@@ List.filter (( <> ) "")
@@ List.map String.trim
@@ List.map Dream.html_escape tag_list
in
let date = Unix.time () in
let comment, citations = parse_comment comment in
let* nick = User.get_nick user_id in
let reply =
{ id
; parent_id
; date
; user_id
; nick
; comment
; image_info
; tags = tag_list
; replies = []
; citations
}
in
Ok reply
let build_op ~comment ~image_info ~tag_list ~categories ~subject ~lat ~lng
user_id =
2022-01-25 14:07:28 +01:00
let subject = Dream.html_escape subject in
2022-03-09 14:36:19 +01:00
if List.exists (fun s -> not (List.mem s App.categories)) categories then
Error "Invalid category"
2022-01-25 14:07:28 +01:00
else
2022-03-09 14:36:19 +01:00
let tag_list = categories @ tag_list in
(* TODO latlng validation? *)
let is_valid_latlng = true in
if not is_valid_latlng then Error "Invalid coordinate"
else if String.length subject > 600 then Error "Invalid subject"
else
let thread_data = { subject; lng; lat } in
2022-03-16 03:06:59 +01:00
let* reply = build_reply ~comment ~image_info ~tag_list user_id in
let op = (thread_data, reply) in
2022-03-09 14:36:19 +01:00
Ok op
2022-01-29 09:23:57 +01:00
2022-03-16 03:06:59 +01:00
let build_image image_input =
let* name, alt, content = clean_image image_input in
2022-03-15 00:12:36 +01:00
let* thumbnail = make_thumbnail content in
let image = { name; alt; content; thumbnail } in
2022-03-16 03:06:59 +01:00
Ok image
let make_post ~comment ?image_input ~tags ~op_or_reply_data user_id =
let tag_list = String.split_on_char ',' tags in
let* image, image_info =
match image_input with
| None -> Ok (None, None)
| Some image_input ->
let* image = build_image image_input in
Ok (Some image, Some (image.name, image.alt))
in
let* post =
match op_or_reply_data with
| `Reply_data parent_id ->
let* reply =
build_reply ~comment ~image_info ~tag_list ~parent_id user_id
in
Ok (Post reply)
| `Op_data (categories, subject, lat, lng) ->
let* thread_data, reply =
build_op ~comment ~image_info ~tag_list ~categories ~subject ~lat ~lng
user_id
in
Ok (Op (thread_data, reply))
2022-03-09 14:36:19 +01:00
in
2022-03-16 03:06:59 +01:00
upload_post ~image post
let get_post_image_content id =
let^? content = Db.find_opt Q.get_post_image_content id in
2022-01-12 15:38:30 +01:00
Ok content
2022-03-15 00:12:36 +01:00
let get_post_image_thumbnail id =
let^? content = Db.find_opt Q.get_post_image_thumbnail id in
Ok content
2022-02-23 14:30:06 +01:00
let thread_exist id = Result.is_ok (Db.find Q.get_is_thread id)
(* true if post is an op too *)
2022-02-23 14:30:06 +01:00
let post_exist id = Result.is_ok (Db.find Q.get_is_post id)
let get_post id =
let^ parent_id = Db.find Q.get_post_thread id in
2022-03-08 21:20:01 +01:00
let^ user_id = Db.find Q.get_post_user_id id in
let* nick = User.get_nick user_id in
let^ comment = Db.find Q.get_post_comment id in
let^ date = Db.find Q.get_post_date id in
let^ image_info = Db.find_opt Q.get_post_image_info id in
let^ tags = Db.collect_list Q.get_post_tags id in
let^ replies = Db.collect_list Q.get_post_replies id in
let^ citations = Db.collect_list Q.get_post_citations id in
let reply =
2022-03-06 19:23:52 +01:00
{ id
; parent_id
; date
2022-03-08 21:20:01 +01:00
; user_id
2022-03-06 19:23:52 +01:00
; nick
; comment
; image_info
; tags
; replies
; citations
}
in
Ok reply
let get_thread_data id =
2022-02-23 14:30:06 +01:00
if thread_exist id then
let^? subject, lat, lng = Db.find_opt Q.get_thread_info id in
let thread_data = { subject; lat; lng } in
Ok thread_data
else Error "not an op"
let get_op id =
let* thread_data = get_thread_data id in
2022-02-21 02:24:17 +01:00
let* post = get_post id in
Ok (thread_data, post)
let get_posts ids = unwrap_list get_post ids
let get_ops ids = unwrap_list get_op ids
2022-02-21 09:46:27 +01:00
2022-03-08 21:20:01 +01:00
let try_delete_post ~user_id id =
2022-02-21 09:46:27 +01:00
let* post = get_post id in
2022-03-08 21:20:01 +01:00
if post.user_id = user_id || User.is_admin user_id then
2022-02-21 09:46:27 +01:00
let^ () = Db.exec Q.delete_post id in
Ok ()
else Error "You can only delete your posts"
2022-02-22 07:10:52 +01:00
2022-03-08 21:20:01 +01:00
let report ~user_id ~reason id =
2022-02-27 19:58:32 +01:00
if not (post_exist id) then Error "This post exists not"
2022-02-23 14:30:06 +01:00
else if String.length reason > 2000 then Error "Your reason is too long.."
2022-02-22 07:10:52 +01:00
else
2022-02-23 14:30:06 +01:00
let reason = Dream.html_escape reason in
let date = Unix.time () in
2022-03-08 21:20:01 +01:00
let^ () = Db.exec Q.upload_report (user_id, reason, date, id) in
2022-02-22 07:10:52 +01:00
Ok ()
2022-02-23 22:39:48 +01:00
let ignore_report id =
let^ () = Db.exec Q.ignore_report id in
Ok ()
let get_reports () =
let^ reports = Db.collect_list Q.get_reports () in
let* posts =
2022-03-08 21:20:01 +01:00
unwrap_list (fun (_reporter_id, _reason, _date, id) -> get_post id) reports
in
(* add reporter_nick to reports so we can display it *)
let* reports =
unwrap_list
(fun (reporter_id, reason, date, id) ->
let* reporter_nick = User.get_nick reporter_id in
Ok (reporter_id, reporter_nick, reason, date, id) )
reports
2022-02-23 22:39:48 +01:00
in
Ok (posts, reports)