add categories

This commit is contained in:
Swrup 2022-03-09 14:36:19 +01:00
parent 4064fced95
commit b5fc7e9a8d
6 changed files with 85 additions and 25 deletions

View file

@ -78,9 +78,13 @@ let log =
let () = Dream.log "log: %b" log let () = Dream.log "log: %b" log
let admins = let get_dirs name =
let dirs = Scfg.Query.get_dirs "admin" config in let dirs = Scfg.Query.get_dirs name config in
List.map List.map
(fun dir -> (fun dir ->
Result.fold ~error:failwith ~ok:Fun.id (Scfg.Query.get_param 0 dir) ) Result.fold ~error:failwith ~ok:Fun.id (Scfg.Query.get_param 0 dir) )
dirs dirs
let admins = get_dirs "admin"
let categories = get_dirs "category"

View file

@ -343,9 +343,8 @@ let upload_post ?image_content post =
let^ () = Db.exec Q.upload_thread_info (id, subject, lat, lng) in let^ () = Db.exec Q.upload_thread_info (id, subject, lat, lng) in
Ok id Ok id
let build_reply ~comment ?image ~tags ?parent_id user_id = let build_reply ~comment ?image ~tag_list ?parent_id user_id =
let comment = Dream.html_escape comment in let comment = Dream.html_escape comment in
let tags = Dream.html_escape tags in
let id = Uuidm.to_string (Uuidm.v4_gen random_state ()) in 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 *) (* parent_id is None if this reply is supposed to be a new thread *)
let parent_id = Option.value parent_id ~default:id in let parent_id = Option.value parent_id ~default:id in
@ -355,7 +354,9 @@ let build_reply ~comment ?image ~tags ?parent_id user_id =
match parse_image image with match parse_image image with
| Error e -> Error e | Error e -> Error e
| Ok image -> | Ok image ->
if String.length tags > 1000 then Error "invalid tags" 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 else
let image_info = let image_info =
match image with match image with
@ -367,7 +368,7 @@ let build_reply ~comment ?image ~tags ?parent_id user_id =
@@ List.sort_uniq String.compare @@ List.sort_uniq String.compare
@@ List.filter (( <> ) "") @@ List.filter (( <> ) "")
@@ List.map String.trim @@ List.map String.trim
@@ Str.split (Str.regexp ",+") tags @@ List.map Dream.html_escape tag_list
in in
let date = Unix.time () in let date = Unix.time () in
let comment, citations = parse_comment comment in let comment, citations = parse_comment comment in
@ -387,31 +388,39 @@ let build_reply ~comment ?image ~tags ?parent_id user_id =
in in
Ok reply Ok reply
let build_op ~comment ?image ~tags ~subject ~lat ~lng user_id = let build_op ~comment ?image ~tag_list ~categories ~subject ~lat ~lng user_id =
let subject = Dream.html_escape subject in let subject = Dream.html_escape subject in
(* TODO latlng validation? *) if List.exists (fun s -> not (List.mem s App.categories)) categories then
let is_valid_latlng = true in Error "Invalid category"
if not is_valid_latlng then Error "Invalid coordinate"
else if String.length subject > 600 then Error "Invalid subject"
else else
let thread_data = { subject; lng; lat } in let tag_list = categories @ tag_list in
let* reply = (* TODO latlng validation? *)
match image with let is_valid_latlng = true in
| Some image -> build_reply ~comment ~image ~tags user_id if not is_valid_latlng then Error "Invalid coordinate"
| None -> build_reply ~comment ~tags user_id else if String.length subject > 600 then Error "Invalid subject"
in else
let op = Op (thread_data, reply) in let thread_data = { subject; lng; lat } in
Ok op let* reply =
match image with
| Some image -> build_reply ~comment ~image ~tag_list user_id
| None -> build_reply ~comment ~tag_list user_id
in
let op = Op (thread_data, reply) in
Ok op
let make_reply ~comment ?image ~tags ~parent_id user_id = let make_reply ~comment ?image ~tags ~parent_id user_id =
let* reply = build_reply ~comment ?image ~tags ~parent_id user_id in let tag_list = Str.split (Str.regexp ",+") tags in
let* reply = build_reply ~comment ?image ~tag_list ~parent_id user_id in
let post = Post reply in let post = Post reply in
match image with match image with
| None -> upload_post post | None -> upload_post post
| Some (_image_info, image_content) -> upload_post ~image_content post | Some (_image_info, image_content) -> upload_post ~image_content post
let make_op ~comment ?image ~tags ~subject ~lat ~lng user_id = let make_op ~comment ?image ~tags ~categories ~subject ~lat ~lng user_id =
let* op = build_op ~comment ?image ~tags ~subject ~lat ~lng user_id in let tag_list = Str.split (Str.regexp ",+") tags in
let* op =
build_op ~comment ?image ~tag_list ~categories ~subject ~lat ~lng user_id
in
match image with match image with
| None -> upload_post op | None -> upload_post op
| Some (_image_info, image_content) -> upload_post ~image_content op | Some (_image_info, image_content) -> upload_post ~image_content op

View file

@ -39,6 +39,7 @@ let f request =
<textarea name="thread-comment" type="text" class="form-control" id="thread-comment" aria-labelledby="thread-comment-label"></textarea> <textarea name="thread-comment" type="text" class="form-control" id="thread-comment" aria-labelledby="thread-comment-label"></textarea>
<br /> <br />
<label for="tags" id="tags-label" class="form-label">Tags</label> <label for="tags" id="tags-label" class="form-label">Tags</label>
<%s! Pp_babillard.pp_checkboxes () %>
<input name="tags" type="text" class="form-control" id="tags" aria-labelledby="tags-label"></input> <input name="tags" type="text" class="form-control" id="tags" aria-labelledby="tags-label"></input>
<br /> <br />
<label for="file" id="file-label" class="form-label">Picture:</label> <label for="file" id="file-label" class="form-label">Picture:</label>

View file

@ -129,6 +129,14 @@ a.preview-link {
padding: 2px; padding: 2px;
} }
.category {
background-color: #FFB300;
border-radius: 4px;
padding: 2px;
font-weight: bold;
font-size: 20px;
}
.off { .off {
display: none; display: none;
} }

View file

@ -1,3 +1,5 @@
include Bindings
let get_title content = let get_title content =
let open Soup in let open Soup in
try try
@ -341,6 +343,7 @@ let babillard_post request =
match%lwt Dream.multipart request with match%lwt Dream.multipart request with
| `Ok | `Ok
[ ("alt", [ (_, alt) ]) [ ("alt", [ (_, alt) ])
; ("category", categories)
; ("file", file) ; ("file", file)
; ("lat-input", [ (_, lat) ]) ; ("lat-input", [ (_, lat) ])
; ("lng-input", [ (_, lng) ]) ; ("lng-input", [ (_, lng) ])
@ -348,17 +351,23 @@ let babillard_post request =
; ("tags", [ (_, tags) ]) ; ("tags", [ (_, tags) ])
; ("thread-comment", [ (_, comment) ]) ; ("thread-comment", [ (_, comment) ])
] -> ( ] -> (
let categories =
List.map (fun (_name, category) -> category) categories
in
match (Float.of_string_opt lat, Float.of_string_opt lng) with match (Float.of_string_opt lat, Float.of_string_opt lng) with
| None, _ -> render_unsafe "Invalide coordinate" request | None, _ -> render_unsafe "Invalide coordinate" request
| _, None -> render_unsafe "Invalide coordinate" request | _, None -> render_unsafe "Invalide coordinate" request
| Some lat, Some lng -> ( | Some lat, Some lng -> (
let res = let res =
match file with match file with
| [] -> Babillard.make_op ~comment ~lat ~lng ~subject ~tags user_id | [] ->
Babillard.make_op ~comment ~lat ~lng ~subject ~tags ~categories
user_id
| _ :: _ :: _ -> Error "More than one image" | _ :: _ :: _ -> Error "More than one image"
| [ (image_name, image_content) ] -> | [ (image_name, image_content) ] ->
let image = ((image_name, alt), image_content) in let image = ((image_name, alt), image_content) in
Babillard.make_op ~comment ~image ~lat ~lng ~subject ~tags user_id Babillard.make_op ~comment ~image ~lat ~lng ~subject ~tags
~categories user_id
in in
match res with match res with
| Ok thread_id -> | Ok thread_id ->

View file

@ -96,11 +96,21 @@ let pp_post fmt t =
user_id nick date id id id post_links_view () user_id nick date id id id post_links_view ()
in in
let pp_print_category fmt category =
Format.fprintf fmt {|<span class="category tag">%s</span>|} category
in
let pp_print_tag fmt tag = let pp_print_tag fmt tag =
Format.fprintf fmt {|<span class="tag">%s</span>|} tag Format.fprintf fmt {|<span class="tag">%s</span>|} tag
in in
let pp_print_tags fmt tags = let pp_print_tags fmt tags =
Format.fprintf fmt {|<div class="tags">%a</div>|} let categories, tags =
List.partition (fun tag -> List.mem tag App.categories) tags
in
let categories = List.sort String.compare categories in
let tags = List.sort String.compare tags in
Format.fprintf fmt {|<div class="tags">%a%a</div>|}
(Format.pp_print_list ~pp_sep:Format.pp_print_space pp_print_category)
categories
(Format.pp_print_list ~pp_sep:Format.pp_print_space pp_print_tag) (Format.pp_print_list ~pp_sep:Format.pp_print_space pp_print_tag)
tags tags
in in
@ -274,6 +284,25 @@ let get_markers () =
in in
Ok markers Ok markers
let pp_checkboxes () =
let pp_checkbox fmt category =
Format.fprintf fmt
{|
<div class="form-check col">
<input name="category" id="category-%s" type="checkbox" class"form-check-input" value="%s">
<label class="form-check-label" for="category-%s">%s</label>
</div>
|}
category category category category
in
Format.asprintf
{|
<div class="row">
%a
</div>|}
(Format.pp_print_list ~pp_sep:Format.pp_print_space pp_checkbox)
App.categories
(* RFC-3339 date-time *) (* RFC-3339 date-time *)
let pp_date fmt date = let pp_date fmt date =
let date = Unix.gmtime date in let date = Unix.gmtime date in