From 1f647374a8cdf3bc5c2d29ff8be277b027925c8c Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Sat, 30 Mar 2024 16:36:54 -0400 Subject: [PATCH] post comments, refactor post loading, hide load more btn --- db/rest/comment/api_comment.sql | 15 +++ db/rest/comment/api_comment_delete.sql | 31 +++++ db/rest/comment/api_comment_insert.sql | 56 +++++++++ db/rest/comment/api_comment_update.sql | 50 +++++++++ db/rest/post/api_post.sql | 15 ++- db/rest/post/api_post_insert.sql | 2 + db/rest/post/api_post_update.sql | 36 +++++- db/rest/rest.sql | 7 ++ db/rest/user/api_user_insert.sql | 15 ++- db/rest/user/api_user_update.sql | 150 ++++++++++++++++++++++++- db/rest/util/_api_trim.sql | 25 +++++ db/rest/util/_api_validate_text.sql | 2 + web/_controller/_util/post.php | 129 +++++++++++++++++++++ web/_controller/apps/home.php | 70 +----------- web/_model/format.php | 2 +- web/_views/apps/home/main.php | 5 +- web/_views/template/comment.php | 7 +- web/_views/template/post.php | 31 +++-- web/_views/template/posts.php | 23 ++++ web/core/database.php | 12 ++ web/public/css/post.css | 4 + web/public/js/shared/post.js | 58 +++++++++- 22 files changed, 647 insertions(+), 98 deletions(-) create mode 100644 db/rest/comment/api_comment.sql create mode 100644 db/rest/comment/api_comment_delete.sql create mode 100644 db/rest/comment/api_comment_insert.sql create mode 100644 db/rest/comment/api_comment_update.sql create mode 100644 db/rest/util/_api_trim.sql create mode 100644 web/_controller/_util/post.php create mode 100644 web/_views/template/posts.php diff --git a/db/rest/comment/api_comment.sql b/db/rest/comment/api_comment.sql new file mode 100644 index 0000000..e50ca2f --- /dev/null +++ b/db/rest/comment/api_comment.sql @@ -0,0 +1,15 @@ +CREATE VIEW api.comment AS + SELECT + c.id, + c.user_id, + c.post_id, + c.content, + c.date + FROM + admin.comment c + ORDER BY id ASC; + +GRANT SELECT ON TABLE api.comment + TO rest_anon, rest_user; +GRANT SELECT ON TABLE admin.comment + TO rest_anon, rest_user; diff --git a/db/rest/comment/api_comment_delete.sql b/db/rest/comment/api_comment_delete.sql new file mode 100644 index 0000000..d7db8a4 --- /dev/null +++ b/db/rest/comment/api_comment_delete.sql @@ -0,0 +1,31 @@ +CREATE FUNCTION _api.comment_delete() +RETURNS TRIGGER +LANGUAGE plpgsql VOLATILE +AS $BODY$ +DECLARE + _user_id INTEGER; +BEGIN + _user_id = _api.get_user_id(); + + IF OLD.user_id <> _user_id THEN + PERFORM _api.raise_deny(); + END IF; + + DELETE FROM admin.comment + WHERE user_id = _user_id + AND id = OLD.id; +END +$BODY$; + +GRANT EXECUTE ON FUNCTION _api.comment_delete() + TO rest_user; +GRANT DELETE ON TABLE api.comment + TO rest_user; +GRANT DELETE ON TABLE admin.comment + TO rest_user; + +CREATE TRIGGER api_comment_delete_trgr + INSTEAD OF DELETE + ON api.comment + FOR EACH ROW + EXECUTE PROCEDURE _api.comment_delete(); diff --git a/db/rest/comment/api_comment_insert.sql b/db/rest/comment/api_comment_insert.sql new file mode 100644 index 0000000..878e194 --- /dev/null +++ b/db/rest/comment/api_comment_insert.sql @@ -0,0 +1,56 @@ +CREATE FUNCTION _api.comment_insert() +RETURNS TRIGGER +LANGUAGE plpgsql VOLATILE +AS $BODY$ +DECLARE + _user_id INTEGER; +BEGIN + _user_id = _api.get_user_id(); + + NEW.content := _api.trim(NEW.content); + PERFORM _api.validate_text( + _text => NEW.content, + _column => 'content', + _min => 1, + _max => 1024 + ); + + PERFORM TRUE + FROM admin.post + WHERE id = NEW.post_id; + + IF NOT FOUND THEN + PERFORM _api.raise( + _msg => 'api_null_post', + _err => 400 + ); + END IF; + + INSERT INTO admin.comment ( + user_id, + post_id, + content + ) VALUES ( + _user_id, + NEW.post_id, + NEW.content + ); + + RETURN NEW; +END +$BODY$; + +GRANT EXECUTE ON FUNCTION _api.comment_insert() + TO rest_user; +GRANT INSERT ON TABLE api.comment + TO rest_user; +GRANT INSERT ON TABLE admin.comment + TO rest_user; +GRANT UPDATE ON TABLE sys.comment_id_seq + TO rest_user; + +CREATE TRIGGER api_comment_insert_trgr + INSTEAD OF INSERT + ON api.comment + FOR EACH ROW + EXECUTE PROCEDURE _api.comment_insert(); diff --git a/db/rest/comment/api_comment_update.sql b/db/rest/comment/api_comment_update.sql new file mode 100644 index 0000000..d6b4aca --- /dev/null +++ b/db/rest/comment/api_comment_update.sql @@ -0,0 +1,50 @@ +CREATE FUNCTION _api.comment_update() +RETURNS TRIGGER +LANGUAGE plpgsql VOLATILE +AS $BODY$ +DECLARE + _user_id INTEGER; + _changed BOOLEAN; +BEGIN + _user_id = _api.get_user_id(); + _changed = FALSE; + + IF OLD.user_id <> _user_id THEN + PERFORM _api.raise_deny(); + END IF; + + NEW.content = COALESCE(NEW.content, OLD.content); + NEW.content := _api.trim(NEW.content); + PERFORM _api.validate_text( + _text => NEW.content, + _column => 'content', + _min => 1, + _max => 1024 + ); + + IF NEW.content IS DISTINCT FROM OLD.content THEN + _changed = TRUE; + END IF; + + IF _changed THEN + UPDATE admin.comment + SET content = NEW.content + WHERE id = OLD.id; + END IF; + + RETURN NEW; +END +$BODY$; + +GRANT EXECUTE ON FUNCTION _api.comment_update() + TO rest_user; +GRANT UPDATE ON TABLE api.comment + TO rest_user; +GRANT UPDATE ON TABLE admin.comment + TO rest_user; + +CREATE TRIGGER api_comment_update_trgr + INSTEAD OF UPDATE + ON api.comment + FOR EACH ROW + EXECUTE PROCEDURE _api.comment_update(); diff --git a/db/rest/post/api_post.sql b/db/rest/post/api_post.sql index b49289c..375f292 100644 --- a/db/rest/post/api_post.sql +++ b/db/rest/post/api_post.sql @@ -3,10 +3,21 @@ CREATE VIEW api.post AS p.id, p.user_id, p.content, - p.date + p.date, + COALESCE(c.cc, 0) + AS comment_count FROM admin.post p - ORDER BY id DESC; + LEFT JOIN ( + SELECT + COUNT(c.id) as cc, + c.post_id + FROM + admin.comment c + GROUP BY + c.post_id + ) c ON p.id = c.post_id + ORDER BY p.id DESC; GRANT SELECT ON TABLE api.post TO rest_anon, rest_user; diff --git a/db/rest/post/api_post_insert.sql b/db/rest/post/api_post_insert.sql index 02b9d8d..8b2eb48 100644 --- a/db/rest/post/api_post_insert.sql +++ b/db/rest/post/api_post_insert.sql @@ -7,6 +7,8 @@ DECLARE BEGIN _user_id = _api.get_user_id(); + NEW.content := _api.trim(NEW.content); + PERFORM _api.validate_text( _text => NEW.content, _column => 'content', diff --git a/db/rest/post/api_post_update.sql b/db/rest/post/api_post_update.sql index 915d0cd..70230d0 100644 --- a/db/rest/post/api_post_update.sql +++ b/db/rest/post/api_post_update.sql @@ -3,13 +3,45 @@ RETURNS TRIGGER LANGUAGE plpgsql VOLATILE AS $BODY$ DECLARE - _length INTEGER; + _user_id INTEGER; + _changed BOOLEAN; BEGIN + _user_id = _api.get_user_id(); + _changed = FALSE; + + IF OLD.user_id <> _user_id THEN + PERFORM _api.raise_deny(); + END IF; + + NEW.content = COALESCE(NEW.content, OLD.content); + NEW.content := _api.trim(NEW.content); + PERFORM _api.validate_text( + _text => NEW.content, + _column => 'content', + _min => 1, + _max => 4096 + ); + + IF NEW.content IS DISTINCT FROM OLD.content THEN + _changed = TRUE; + END IF; + + IF _changed THEN + UPDATE admin.post + SET content = NEW.content + WHERE id = OLD.id; + END IF; + RETURN NEW; END $BODY$; -GRANT EXECUTE ON FUNCTION _api.post_update() TO rest_user; +GRANT EXECUTE ON FUNCTION _api.post_update() + TO rest_user; +GRANT UPDATE ON TABLE api.post + TO rest_user; +GRANT UPDATE ON TABLE admin.post + TO rest_user; CREATE TRIGGER api_post_update_trgr INSTEAD OF UPDATE diff --git a/db/rest/rest.sql b/db/rest/rest.sql index a286f9d..54f5118 100644 --- a/db/rest/rest.sql +++ b/db/rest/rest.sql @@ -14,6 +14,7 @@ GRANT USAGE ON SCHEMA api TO rest_anon, rest_user; GRANT USAGE ON SCHEMA _api TO rest_anon, rest_user; -- util +\i /db/rest/util/_api_trim.sql; \i /db/rest/util/_api_serve_media.sql; \i /db/rest/util/_api_raise.sql; \i /db/rest/util/_api_raise_null.sql; @@ -34,6 +35,12 @@ GRANT USAGE ON SCHEMA _api TO rest_anon, rest_user; \i /db/rest/post/api_post_update.sql; \i /db/rest/post/api_post_delete.sql; +-- comment +\i /db/rest/comment/api_comment.sql; +\i /db/rest/comment/api_comment_insert.sql; +\i /db/rest/comment/api_comment_update.sql; +\i /db/rest/comment/api_comment_delete.sql; + -- login \i /db/rest/login/_api_sign_jwt.sql; \i /db/rest/login/_api_verify_jwt.sql; diff --git a/db/rest/user/api_user_insert.sql b/db/rest/user/api_user_insert.sql index da3ae2d..2297ecd 100644 --- a/db/rest/user/api_user_insert.sql +++ b/db/rest/user/api_user_insert.sql @@ -5,6 +5,16 @@ AS $BODY$ DECLARE _length INTEGER; BEGIN + + NEW.username := _api.trim(NEW.username); + NEW.password := _api.trim(NEW.password); + NEW.first_name := _api.trim(NEW.first_name); + NEW.last_name := _api.trim(NEW.last_name); + NEW.middle_name := _api.trim(NEW.middle_name); + NEW.email := _api.trim(NEW.email); + NEW.gender := _api.trim(NEW.gender); + NEW.profile_bio := _api.trim(NEW.profile_bio); + PERFORM _api.validate_text( _text => NEW.username, _column => 'username', @@ -22,6 +32,7 @@ BEGIN PERFORM _api.validate_text( _text => NEW.password, _column => 'password', + _min => 1, _max => 256 ); @@ -82,8 +93,6 @@ BEGIN email, gender, birth_date, - profile_avatar, - profile_banner, profile_bio ) VALUES ( NEW.username, @@ -94,8 +103,6 @@ BEGIN NEW.email, NEW.gender, NEW.birth_date, - NEW.profile_avatar, - NEW.profile_banner, NEW.profile_bio ); diff --git a/db/rest/user/api_user_update.sql b/db/rest/user/api_user_update.sql index c6e7f4f..28e4368 100644 --- a/db/rest/user/api_user_update.sql +++ b/db/rest/user/api_user_update.sql @@ -3,15 +3,161 @@ RETURNS TRIGGER LANGUAGE plpgsql VOLATILE AS $BODY$ DECLARE - _length INTEGER; + _user_id INTEGER; + _changed BOOLEAN; BEGIN + _user_id = _api.get_user_id(); + _changed = FALSE; + + IF OLD.id <> _user_id THEN + PERFORM _api.raise_deny(); + END IF; + + -- username + NEW.username = COALESCE(NEW.username, OLD.username); + NEW.username := _api.trim(NEW.username); + PERFORM _api.validate_text( + _text => NEW.username, + _column => 'username', + _min => 1, + _max => 24 + ); + + IF NEW.username IS DISTINCT FROM OLD.username THEN + PERFORM TRUE FROM admin.user + WHERE username = NEW.username; + IF FOUND THEN + PERFORM _api.raise_unique('username'); + END IF; + _changed = TRUE; + END IF; + + -- password + SELECT password + INTO OLD.password + FROM admin.user + WHERE id = OLD.id; + + NEW.password = COALESCE(NEW.password, OLD.password); + NEW.password := _api.trim(NEW.password); + PERFORM _api.validate_text( + _text => NEW.password, + _column => 'password', + _min => 1, + _max => 256 + ); + + IF NEW.password IS DISTINCT FROM OLD.password THEN + _changed = TRUE; + END IF; + + -- first name + NEW.first_name = COALESCE(NEW.first_name, OLD.first_name); + NEW.first_name := _api.trim(NEW.first_name); + PERFORM _api.validate_text( + _text => NEW.first_name, + _column => 'first_name', + _max => 256 + ); + + IF NEW.first_name IS DISTINCT FROM OLD.first_name THEN + _changed = TRUE; + END IF; + + -- last name + NEW.last_name = COALESCE(NEW.last_name, OLD.last_name); + NEW.last_name := _api.trim(NEW.last_name); + PERFORM _api.validate_text( + _text => NEW.last_name, + _column => 'last_name', + _max => 256 + ); + + IF NEW.last_name IS DISTINCT FROM OLD.last_name THEN + _changed = TRUE; + END IF; + + -- middle name + NEW.middle_name = COALESCE(NEW.middle_name, OLD.middle_name); + NEW.middle_name := _api.trim(NEW.middle_name); + PERFORM _api.validate_text( + _text => NEW.middle_name, + _column => 'middle_name', + _max => 256 + ); + + IF NEW.middle_name IS DISTINCT FROM OLD.middle_name THEN + _changed = TRUE; + END IF; + + -- email + NEW.email = COALESCE(NEW.email, OLD.email); + NEW.email := _api.trim(NEW.email); + PERFORM _api.validate_text( + _text => NEW.email, + _column => 'email', + _max => 256 + ); + + IF NEW.email IS DISTINCT FROM OLD.email THEN + _changed = TRUE; + END IF; + + -- gender + NEW.gender = COALESCE(NEW.gender, OLD.gender); + NEW.gender := _api.trim(NEW.gender); + PERFORM _api.validate_text( + _text => NEW.gender, + _column => 'gender', + _max => 256 + ); + + IF NEW.gender IS DISTINCT FROM OLD.gender THEN + _changed = TRUE; + END IF; + + -- birth date + NEW.birth_date = COALESCE(NEW.birth_date, OLD.birth_date); + IF NEW.birth_date IS DISTINCT FROM OLD.birth_date THEN + _changed = TRUE; + END IF; + + -- profile bio + NEW.profile_bio = COALESCE(NEW.profile_bio, OLD.profile_bio); + NEW.profile_bio := _api.trim(NEW.profile_bio); + PERFORM _api.validate_text( + _text => NEW.profile_bio, + _column => 'profile_bio', + _max => 2048 + ); + + IF NEW.profile_bio IS DISTINCT FROM OLD.profile_bio THEN + _changed = TRUE; + END IF; + + IF _changed THEN + UPDATE admin.user SET + username = NEW.username, + password = NEW.password, + first_name = NEW.first_name, + last_name = NEW.last_name, + middle_name = NEW.middle_name, + email = NEW.email, + gender = NEW.gender, + birth_date = NEW.birth_date, + profile_bio = NEW.profile_bio + WHERE id = OLD.id; + END IF; + RETURN NEW; END $BODY$; GRANT EXECUTE ON FUNCTION _api.user_update() TO rest_user; -GRANT DELETE ON TABLE api.user +GRANT UPDATE ON TABLE api.user + TO rest_user; +GRANT UPDATE ON TABLE admin.user TO rest_user; CREATE TRIGGER api_user_update_trgr diff --git a/db/rest/util/_api_trim.sql b/db/rest/util/_api_trim.sql new file mode 100644 index 0000000..c972282 --- /dev/null +++ b/db/rest/util/_api_trim.sql @@ -0,0 +1,25 @@ +CREATE FUNCTION _api.trim( + _text TEXT +) +RETURNS TEXT +LANGUAGE plpgsql VOLATILE +AS $BODY$ +DECLARE + _new TEXT; +BEGIN + + IF _text IS NULL THEN + RETURN NULL; + END IF; + + _new = _text; + _new = TRIM(_new); + _new = REGEXP_REPLACE(_new, '^(?: |\r|\n)*', ''); + _new = REGEXP_REPLACE(_new, '(?: |\r|\n)*$', ''); + + RETURN _new; +END +$BODY$; + +GRANT EXECUTE ON FUNCTION _api.trim(TEXT) + TO rest_anon, rest_user; diff --git a/db/rest/util/_api_validate_text.sql b/db/rest/util/_api_validate_text.sql index e4a6a7b..ff3a227 100644 --- a/db/rest/util/_api_validate_text.sql +++ b/db/rest/util/_api_validate_text.sql @@ -33,6 +33,7 @@ BEGIN _detail => _column, _hint => _min || '' ); + RETURN FALSE; END IF; IF _max IS NOT NULL AND _length > _max THEN @@ -41,6 +42,7 @@ BEGIN _detail => _column, _hint => _max || '' ); + RETURN FALSE; END IF; RETURN TRUE; diff --git a/web/_controller/_util/post.php b/web/_controller/_util/post.php new file mode 100644 index 0000000..b128d67 --- /dev/null +++ b/web/_controller/_util/post.php @@ -0,0 +1,129 @@ +request_model = $this->load->model('request'); + $this->cache_model = $this->load->model('cache'); + $this->page_size = 10; + } + + public function index(): void { + $this->view('template/posts'); + } + + /** + * @return array + */ + public function posts(): array { + $page = $this->request_model->get_int('page', 0); + $max = $this->request_model->get_int('max'); + $offset = $page * $this->page_size; + + $user = $this->main->user(); + + $query = $this->db; + + if ($user) { + $query = $query->select('p.*, l.post_id IS NOT NULL as liked'); + } else { + $query = $query->select('p.*, FALSE as liked'); + } + + $query = $query->from('api.post p'); + + if ($user) { + $query = $query->join('admin.like l', 'p.id = l.post_id AND l.user_id') + ->eq($user['id']); + } + + if ($max) { + $query = $query + ->where('id')->le($max); + } + + $posts = $query + ->limit($this->page_size) + ->offset($offset) + ->rows(); + + $users = $this->cache_model->get_users($posts); + $max = 0; + + foreach ($posts as $post) { + $max = max($max, $post['id']); + $data = array(); + $data['page_size'] = $this->page_size; + $data['user'] = $users[$post['user_id']]; + $data['post'] = $post; + $this->view('template/post', $data); + } + + $pc = $this->db + ->select('COUNT(p.id) as pc') + ->from('api.post p') + ->row()['pc']; + + + return array( + 'loaded' => count($posts), + 'total' => $pc, + 'page_size' => $this->page_size, + 'max' => $max, + ); + } + + /** + * @return array + */ + public function comments(): array { + $page = $this->request_model->get_int('page', 0); + $max = $this->request_model->get_int('max'); + $id = $this->request_model->get_int('id', 0); + $offset = $page * $this->page_size; + + $query = $this->db + ->select('*') + ->from('api.comment') + ->where('post_id') + ->eq($id); + + if ($max) { + $query = $query + ->and() + ->where('id') + ->le($max); + } + + $comments = $query + ->limit($this->page_size) + ->offset($offset) + ->rows(); + + $users = $this->cache_model->get_users($comments); + $max = 0; + + foreach ($comments as $comment) { + $max = max($max, $comment['id']); + $data = array(); + $data['user'] = $users[$comment['user_id']]; + $data['comment'] = $comment; + $this->view('template/comment', $data); + } + + return array( + 'loaded' => count($comments), + 'page_size' => $this->page_size, + 'max' => $max, + ); + } +} diff --git a/web/_controller/apps/home.php b/web/_controller/apps/home.php index 25c8c4e..edf7e2b 100644 --- a/web/_controller/apps/home.php +++ b/web/_controller/apps/home.php @@ -4,17 +4,13 @@ class Home_controller extends Controller { // the home model private $home_model; - // the request model - private $request_model; - - // the caceh model - private $cache_model; + // the post controller + protected $post_controller; function __construct($load) { parent::__construct($load); $this->home_model = $this->load->model('apps/home'); - $this->request_model = $this->load->model('request'); - $this->cache_model = $this->load->model('cache'); + $this->post_controller = $this->load->controller('_util/post'); } public function index(): void { @@ -24,66 +20,6 @@ class Home_controller extends Controller { $this->view('apps/home/main', $data); } - public function posts(): void { - $page = $this->request_model->get_int('page', 0); - $page_size = 20; - $offset = $page * $page_size; - - $user = $this->main->user(); - - $query = $this->db; - - if ($user) { - $query = $query->select('p.*, l.post_id IS NOT NULL as liked'); - } else { - $query = $query->select('p.*, FALSE as liked'); - } - - $query = $query->from('api.post p'); - - if ($user) { - $query = $query->join('admin.like l', 'p.id = l.post_id') - ->where('l.user_id')->eq($user['id']) - ->or()->where('l.user_id IS NULL'); - } - - $posts = $query->limit($page_size) - ->offset($offset) - ->rows(); - - $users = $this->cache_model->get_users($posts); - - foreach ($posts as $post) { - $data = array(); - $data['user'] = $users[$post['user_id']]; - $data['post'] = $post; - $this->view('template/post', $data); - } - } - - public function comments(): void { - $page = $this->request_model->get_int('page', 0); - $id = $this->request_model->get_int('id'); - $page_size = 20; - $offset = $page * $page_size; - - $comments = $this->db - ->select('*') - ->from('admin.comment') - ->limit($page_size) - ->offset($offset) - ->rows(); - - $users = $this->cache_model->get_users($comments); - - foreach ($comments as $comment) { - $data = array(); - $data['user'] = $users[$comment['user_id']]; - $data['comment'] = $comment; - $this->view('template/comment', $data); - } - } - } ?> diff --git a/web/_model/format.php b/web/_model/format.php index d8c7480..52b51be 100644 --- a/web/_model/format.php +++ b/web/_model/format.php @@ -1,5 +1,5 @@ -
- posts()?> -
- + post_controller->index(); ?> diff --git a/web/_views/template/comment.php b/web/_views/template/comment.php index 943f232..20032b2 100644 --- a/web/_views/template/comment.php +++ b/web/_views/template/comment.php @@ -1,11 +1,14 @@ +load->model('format'); +?>
view('template/pfp', array('user' => $user))?>
- main->display_name($user)?> - main->display_date($comment['date'])?> + name($user)?> + date($comment['date'])?>
diff --git a/web/_views/template/post.php b/web/_views/template/post.php index 40a3c1d..4fbf485 100644 --- a/web/_views/template/post.php +++ b/web/_views/template/post.php @@ -29,25 +29,40 @@
comments(); - ilang('action_load_comments', - class: 'action-load-comments btn btn-line mt', - attrs: array('postId' => $post['id']) - ); + $cdata = $this->comments(); + + $loaded = $cdata['loaded']; + $max = $cdata['max']; + $page_size = $cdata['page_size']; + $total = $post['comment_count']; + + if ($loaded >= $page_size && $page_size < $total) { + ilang('action_load_comments', + class: 'action-load-comments btn btn-line mt', + attrs: array( + 'postId' => $post['id'], + 'loaded' => $loaded, + 'pageSize' => $page_size, + 'commentCount' => $total, + 'commentMax' => $max, + ) + ); + } + ?>
view('template/pfp', array('user' => $user))?> -
+ +posts(); + + $loaded = $pdata['loaded']; + $page_size = $pdata['page_size']; + $total = $pdata['total']; + $max = $pdata['max']; + + if ($loaded >= $page_size && $page_size < $total) { + ilang('action_load_posts', + id: 'action-load-posts', + class: 'btn btn-line mb', + attrs: array( + 'loaded' => $loaded, + 'pageSize' => $page_size, + 'postCount' => $total, + 'postMax' => $max, + ) + ); + } +?> +
diff --git a/web/core/database.php b/web/core/database.php index 4b44e86..079b0de 100644 --- a/web/core/database.php +++ b/web/core/database.php @@ -69,6 +69,18 @@ class DatabaseQuery { return $this; } + public function lt($item) { + $this->query .= "< ?\n"; + array_push($this->param, $item); + return $this; + } + + public function le($item) { + $this->query .= "<= ?\n"; + array_push($this->param, $item); + return $this; + } + public function where_in($column, $array) { if (!$this->where) { $this->where = TRUE; diff --git a/web/public/css/post.css b/web/public/css/post.css index 6ad14ba..4030da3 100644 --- a/web/public/css/post.css +++ b/web/public/css/post.css @@ -10,3 +10,7 @@ .action-load-comments { margin-left: 4rem; } + +#action-load-posts { + justify-content: center; +} diff --git a/web/public/js/shared/post.js b/web/public/js/shared/post.js index afbeaf0..f22dd99 100644 --- a/web/public/js/shared/post.js +++ b/web/public/js/shared/post.js @@ -5,14 +5,28 @@ observe('#main-content', '.action-load-comments', function(me) { page = '1'; } let newPage = Number(page) + 1; - let id = me.attr('postId'); me.attr('page', newPage + ''); - let url = '/home/comments?page=' + page + '&id=' + id; + + let postId = me.attr('postId'); + let loaded = Number(me.attr('loaded')); + let pageSize = Number(me.attr('pageSize')); + let commmentCount = Number(me.attr('commentCount')); + let commentMax = Number(me.attr('commentMax')); + + let url = '/_util/post/comments?page=' + page + '&id=' + postId + '&max' + commentMax; $.get(url, function (data) { if (data === '') { me.remove(); + return; + } + + $(data).insertBefore(me); + + loaded += pageSize; + if (loaded >= commmentCount) { + me.remove(); } else { - $(me).prepend(data); + me.attr('loaded', loaded + ''); } }); }); @@ -26,13 +40,45 @@ observe('#main-content', '#action-load-posts', function(me) { } let newPage = Number(page) + 1; me.attr('page', newPage + ''); - let url = '/home/posts?page=' + page; - $.get(url, function (data) { + + let loaded = Number(me.attr('loaded')); + let pageSize = Number(me.attr('pageSize')); + let postCount = Number(me.attr('postCount')); + let postMax = Number(me.attr('postMax')); + + let url = '/_util/post/posts?page=' + page + '&max=' + postMax; + $.get(url, function (data) { if (data === '') { me.remove(); + return; + } + + $(data).insertBefore(me); + + loaded += pageSize; + if (loaded >= postCount) { + me.remove(); } else { - $('#post-container').append(data); + me.attr('loaded', loaded + ''); } }); }); }); + +observe('#main-content', '.action-new-comment-form', function(me) { + me.on('submit', function(e) { + e.preventDefault(); + let input = me.find('.action-new-comment'); + let content = input.val(); + let post_id = input.attr('postId'); + $.ajax({ + url: '/api/comment', + method: 'POST', + data: JSON.stringify({ post_id, content }), + success: function(_data) { + window.location.reload(); + }, + error: errorToast + }); + }); +});