diff options
author | Tor Andersson <tor@ccxvii.net> | 2021-11-09 22:33:53 +0100 |
---|---|---|
committer | Tor Andersson <tor@ccxvii.net> | 2021-11-09 22:59:49 +0100 |
commit | 70289448796f6649d74a2ec22b300c3b0075b762 (patch) | |
tree | 87959c4ef3469070bdb36db2ea1de723553a83ef | |
parent | 86ee8f02d4230199378eb055a5a89c15844208c9 (diff) | |
download | server-70289448796f6649d74a2ec22b300c3b0075b762.tar.gz |
Show user profiles.
-rw-r--r-- | server.js | 52 | ||||
-rw-r--r-- | tools/sql/schema.txt | 1 | ||||
-rw-r--r-- | views/forum_thread.ejs | 3 | ||||
-rw-r--r-- | views/forum_view.ejs | 9 | ||||
-rw-r--r-- | views/games.ejs | 4 | ||||
-rw-r--r-- | views/info.ejs | 9 | ||||
-rw-r--r-- | views/message_inbox.ejs | 10 | ||||
-rw-r--r-- | views/message_outbox.ejs | 15 | ||||
-rw-r--r-- | views/profile.ejs | 15 | ||||
-rw-r--r-- | views/users.ejs | 2 |
10 files changed, 92 insertions, 28 deletions
@@ -129,6 +129,18 @@ function humanize(rows) { } } +function linkify_player_names(games) { + for (let i = 0; i < games.length; ++i) { + let game = games[i]; + if (game.player_names) { + game.player_names = game.player_names + .split(", ") + .map(x => `<a href="/user/${x}">${x}</a>`) + .join(", "); + } + } +} + function humanize_one(row) { row.ctime = human_date(row.ctime); row.mtime = human_date(row.mtime); @@ -192,6 +204,8 @@ const sql_subscribe = db.prepare("UPDATE users SET notifications = 1 WHERE user_ const sql_unsubscribe = db.prepare("UPDATE users SET notifications = 0 WHERE user_id = ?"); const sql_count_unread_messages = db.prepare("SELECT COUNT(*) FROM messages WHERE to_id = ? AND read = 0 AND deleted_from_inbox = 0").pluck(); +const sql_fetch_user_by_name = db.prepare("SELECT * FROM users WHERE user_id = ? OR name = ?"); +const sql_fetch_user_by_id = db.prepare("SELECT * FROM users WHERE user_id = ?"); passport.serializeUser(function (user, done) { return done(null, user.user_id); @@ -346,6 +360,12 @@ app.get('/change_mail', must_be_logged_in, function (req, res) { res.render('change_mail.ejs', { user: req.user, message: req.flash('message') }); }); +app.get('/change_about', must_be_logged_in, function (req, res) { + LOG(req, "GET /change_about"); + let about = sql_fetch_user_by_id.get(req.user.user_id).about; + res.render('change_about.ejs', { user: req.user, about: about || "", message: req.flash('message') }); +}); + app.get('/subscribe', must_be_logged_in, function (req, res) { LOG(req, "GET /subscribe"); sql_subscribe.run(req.user.user_id); @@ -498,6 +518,7 @@ const sql_change_name = db.prepare("UPDATE users SET name = ? WHERE user_id = ?" const sql_is_mail_taken = db.prepare("SELECT EXISTS ( SELECT 1 FROM users WHERE mail = ? )").pluck(); const sql_change_mail = db.prepare("UPDATE users SET mail = ? WHERE user_id = ?"); +const sql_change_about = db.prepare("UPDATE users SET about = ? WHERE user_id = ?"); app.post('/change_name', must_be_logged_in, function (req, res) { try { @@ -543,6 +564,18 @@ app.post('/change_mail', must_be_logged_in, function (req, res) { } }); +app.post('/change_about', must_be_logged_in, function (req, res) { + try { + LOG(req, "POST /change_about", req.user.name); + sql_change_about.run(req.body.about, req.user.user_id); + return res.redirect('/profile'); + } catch (err) { + console.log(err); + req.flash('message', err.message); + return res.redirect('/change_about'); + } +}); + /* * GAME LOBBY */ @@ -661,6 +694,7 @@ app.get('/profile', must_be_logged_in, function (req, res) { let avatar = get_avatar(req.user.mail); let games = QUERY_LIST_GAMES_OF_USER.all({user_id: req.user.user_id}); humanize(games); + linkify_player_names(games); let open_games = games.filter(game => game.status === 0); let active_games = games.filter(game => game.status === 1); let finished_games = games.filter(game => game.status === 2); @@ -682,6 +716,7 @@ app.get('/info/:title_id', function (req, res) { if (req.isAuthenticated()) { let games = QUERY_LIST_GAMES_OF_TITLE.all({user_id: req.user.user_id, title_id: title_id}); humanize(games); + linkify_player_names(games); let open_games = games.filter(game => game.status === 0); let active_games = games.filter(game => game.status === 1); let finished_games = games.filter(game => game.status === 2); @@ -1486,6 +1521,15 @@ app.get('/games', must_be_logged_in, function (req, res) { }); }); +app.get('/user/:who_id', function (req, res) { + LOG(req, "GET /user/" + req.params.who_id); + let who = sql_fetch_user_by_name.get(req.params.who_id, req.params.who_id); + who.avatar = get_avatar(who.mail); + who.ctime = human_date(who.ctime); + who.atime = human_date(who.atime); + res.render('user.ejs', { user: req.user, who: who, message: req.flash('message') }); +}); + // FORUM const FORUM_PAGE_SIZE = 15; @@ -1621,6 +1665,7 @@ app.post('/forum/reply/:thread_id', must_be_logged_in, function (req, res) { }); // MESSAGES + const MESSAGE_GET_USER = db.prepare("SELECT user_id, name, mail, notifications FROM users WHERE name = ?"); const MESSAGE_GET_USER_ID = db.prepare("SELECT user_id FROM users WHERE name = ?").pluck(); const MESSAGE_GET_USER_NAME = db.prepare("SELECT name FROM users WHERE user_id = ?").pluck(); @@ -1642,6 +1687,7 @@ const MESSAGE_SEND = db.prepare("INSERT INTO messages ( from_id, to_id, subject, const MESSAGE_MARK_READ = db.prepare("UPDATE messages SET read = 1 WHERE message_id = ?"); const MESSAGE_DELETE_INBOX = db.prepare("UPDATE messages SET deleted_from_inbox = 1 WHERE message_id = ? AND to_id = ?"); const MESSAGE_DELETE_OUTBOX = db.prepare("UPDATE messages SET deleted_from_outbox = 1 WHERE message_id = ? AND from_id = ?"); +const MESSAGE_DELETE_ALL_OUTBOX = db.prepare("UPDATE messages SET deleted_from_outbox = 1 WHERE from_id = ?"); app.get('/inbox', must_be_logged_in, function (req, res) { LOG(req, "GET /inbox"); @@ -1770,3 +1816,9 @@ app.get('/message/delete/:message_id', must_be_logged_in, function (req, res) { MESSAGE_DELETE_OUTBOX.run(message_id, req.user.user_id); res.redirect('/inbox'); }); + +app.get('/outbox/delete', must_be_logged_in, function (req, res) { + LOG(req, "POST /outbox/delete"); + MESSAGE_DELETE_ALL_OUTBOX.run(req.user.user_id); + res.redirect('/outbox'); +}); diff --git a/tools/sql/schema.txt b/tools/sql/schema.txt index cd1a7ee..6344470 100644 --- a/tools/sql/schema.txt +++ b/tools/sql/schema.txt @@ -2,6 +2,7 @@ CREATE TABLE IF NOT EXISTS users ( user_id INTEGER PRIMARY KEY, name TEXT UNIQUE COLLATE NOCASE, mail TEXT UNIQUE COLLATE NOCASE, + about TEXT, password TEXT, salt TEXT, ctime TIMESTAMP, diff --git a/views/forum_thread.ejs b/views/forum_thread.ejs index fad8829..0041f20 100644 --- a/views/forum_thread.ejs +++ b/views/forum_thread.ejs @@ -2,6 +2,7 @@ <style> table { width: 100%; max-width: 50em; } td.body { white-space: pre-wrap; padding: 10px 10px; } +th a { color: black; text-decoration: none; } th.author { border-right: none; } th.time { text-align: right; border-left: none; font-weight: normal; } td.edit { text-align: right; border: none; } @@ -10,7 +11,7 @@ td.edit { text-align: right; border: none; } <p> <table> <tr> -<th class="nowrap author"><%= row.author_name %> +<th class="nowrap author"><a href="/user/<%- row.author_name %>"><%= row.author_name %></a> <th class="nowrap time"><%= row.ctime %> <%= row.edited ? "(edited " + row.mtime + ")" : "" %> <tr> diff --git a/views/forum_view.ejs b/views/forum_view.ejs index 7c3de75..5f04f3f 100644 --- a/views/forum_view.ejs +++ b/views/forum_view.ejs @@ -3,16 +3,19 @@ table { width: 100%; max-width: 60em; } td a { color: black; text-decoration: none; } tfoot td { background-color: gainsboro; } +th.replies { width: 3em; } +th.time { width: 5em; } +th.author { width: 10em; } </style> <table> <thead> -<tr><th>Subject<th>Author -<th>Replies<th>Time +<tr><th class="subject">Subject<th class="author">Author +<th class="replies">Replies<th class="time">Time </thead> <% threads.forEach((row) => { %> <tr> <td class="ellipsis"><a href="/forum/thread/<%- row.thread_id %>"><%= row.subject %></a> -<td class="nowrap"><%= row.author_name %> +<td class="nowrap"><a href="/user/<%- row.author_name %>"><%= row.author_name %></a> <td><%= row.reply_count %> <td class="nowrap"><%= row.mtime %> <% }); %> diff --git a/views/games.ejs b/views/games.ejs index e25df1f..b74dbba 100644 --- a/views/games.ejs +++ b/views/games.ejs @@ -12,7 +12,7 @@ td.nowrap a { color: black; text-decoration: none; } <td><%= row.game_id %> <td class="nowrap"><a href="/info/<%= row.title_id %>"><%= row.title_name %></a> <td><%= row.scenario %> -<td><%= row.player_names || row.owner_name %> +<td><%- row.player_names || row.owner_name %> <td><%= row.description %> <td class="nowrap"><%= row.ctime %> <td><a href="/join/<%= row.game_id %>">Join</a> @@ -30,7 +30,7 @@ td.nowrap a { color: black; text-decoration: none; } <td><%= row.game_id %> <td class="nowrap"><a href="/info/<%= row.title_id %>"><%= row.title_name %></a> <td><%= row.scenario %> -<td><%= row.player_names %> +<td><%- row.player_names %> <td><%= row.description %> <td class="nowrap"><%= row.mtime %> <td class="<%= row.is_your_turn ? "is_your_turn" : "" %>"><%= row.active_role %> diff --git a/views/info.ejs b/views/info.ejs index 778974e..159e732 100644 --- a/views/info.ejs +++ b/views/info.ejs @@ -1,4 +1,7 @@ <%- include('header', { title: title.title_name, refresh: (user ? 300 : 0) }) %> +<style> +td.names a { color: black; text-decoration: none; } +</style> <img class="logo" src="/<%= title.title_id %>/cover.jpg"> <%- include('../public/' + title.title_id + '/about.html') %> <p> @@ -15,7 +18,7 @@ Read more about the game on <tr> <td><%= row.game_id %> <td><%= row.scenario %> -<td><%= row.player_names || row.owner_name %> +<td class="names"><%- row.player_names || `<a href="/user/${row.owner_name}">${row.owner_name}</a>` %> <td><%= row.description %> <td class="nowrap"><%= row.ctime %> <td><a href="/join/<%= row.game_id %>">Join</a> @@ -35,7 +38,7 @@ Read more about the game on <tr> <td><%= row.game_id %> <td><%= row.scenario %> -<td><%= row.player_names %> +<td class="names"><%- row.player_names %> <td><%= row.description %> <td class="nowrap"><%= row.mtime %> <td class="<%= row.is_your_turn ? "is_your_turn" : "" %>"><%= row.active_role %> @@ -52,7 +55,7 @@ Read more about the game on <tr> <td><%= row.game_id %> <td><%= row.scenario %> -<td><%= row.player_names %> +<td class="names"><%- row.player_names %> <td><%= row.description %> <td class="nowrap"><%= row.mtime %> <td><%= row.result %> diff --git a/views/message_inbox.ejs b/views/message_inbox.ejs index 91490ac..16b0c46 100644 --- a/views/message_inbox.ejs +++ b/views/message_inbox.ejs @@ -1,23 +1,21 @@ <%- include('header', { title: "Inbox" }) %> <style> table { width: 100%; max-width: 50em; } -tr.unread { background-color: lemonchiffon; } +tr.unread { background-color: lightyellow; } td.from { width: 5em; } td.time { text-align: right; width: 5em; } td a { color:black; text-decoration: none; } </style> -<p> -» <a href="/message/send">Send message</a> -<br> -» <a href="/outbox">Outbox</a> +<p><a href="/message/send">Send message</a> <table> <tr><th>From<th>Subject<th>Date <% if (messages.length > 0) { messages.forEach((row) => { %> <tr class="<%- row.read ? "read" : "unread" %>"> -<td class="nowrap from"><%= row.from_name %> +<td class="nowrap from"><a href="/user/<%- row.from_name %>"><%= row.from_name %></a> <td class="subject"><a href="/message/read/<%- row.message_id %>"><%= row.subject %></a> <td class="nowrap time"><%= row.time %> <% }); } else { %> <tr><td colspan="3">No messages</td> <% } %> </table> +<p><a href="/outbox">Outbox</a> diff --git a/views/message_outbox.ejs b/views/message_outbox.ejs index c460bd3..e5c53e3 100644 --- a/views/message_outbox.ejs +++ b/views/message_outbox.ejs @@ -1,4 +1,11 @@ <%- include('header', { title: "Outbox" }) %> +<script> +function delete_all() { + let warning = "Are you sure you want to delete ALL the messages?"; + if (window.confirm(warning)) + window.location.href = "/outbox/delete"; +} +</script> <style> table { width: 100%; max-width: 50em; } tr.unread { background-color: lemonchiffon; } @@ -6,18 +13,16 @@ td.to { width: 5em; } td.time { text-align: right; width: 5em; } td a { color:black; text-decoration: none; } </style> -<p> -» <a href="/message/send">Send message</a> -<br> -» <a href="/inbox">Inbox</a> <table> <tr><th>To<th>Subject<th>Date <% if (messages.length > 0) { messages.forEach((row) => { %> <tr class="<%- row.read ? "read" : "unread" %>"> -<td class="nowrap to"><%= row.to_name %> +<td class="nowrap to"><a href="/user/<%- row.to_name %>"><%= row.to_name %></a> <td class="subject"><a href="/message/read/<%- row.message_id %>"><%= row.subject %></a> <td class="nowrap time"><%= row.time %> <% }); } else { %> <tr><td colspan="3">No messages</td> <% } %> </table> +<p> +<button onclick="delete_all()">Delete all</button> diff --git a/views/profile.ejs b/views/profile.ejs index 8d03234..3c49014 100644 --- a/views/profile.ejs +++ b/views/profile.ejs @@ -1,6 +1,6 @@ <%- include('header', { title: "Rally the Troops!", refresh: (active_games.length > 0 ? 300 : 0) }) %> <style> -td.nowrap a { color: black; text-decoration: none; } +td.game a, td.names a { color: black; text-decoration: none; } .logo { width: 80px; height: 80px; } </style> @@ -23,6 +23,7 @@ Your mail address is <%= user.mail %>. <li><a href="/change_password">Change password</a> <li><a href="/change_mail">Change mail address</a> <li><a href="/change_name">Change name</a> +<li><a href="/change_about">Change profile text</a> <li><a href="/logout">Logout</a> </ul> @@ -33,9 +34,9 @@ Your mail address is <%= user.mail %>. <% open_games.forEach((row) => { %> <tr> <td><%= row.game_id %> -<td class="nowrap"><a href="/info/<%= row.title_id %>"><%= row.title_name %></a> +<td class="nowrap game"><a href="/info/<%= row.title_id %>"><%= row.title_name %></a> <td><%= row.scenario %> -<td><%= row.player_names %> +<td class="names"><%- row.player_names %> <td><%= row.description %> <td class="nowrap"><%= row.ctime %> <td><a href="/join/<%= row.game_id %>">Join</a> @@ -50,9 +51,9 @@ Your mail address is <%= user.mail %>. <% active_games.forEach((row) => { %> <tr> <td><%= row.game_id %> -<td class="nowrap"><a href="/info/<%= row.title_id %>"><%= row.title_name %></a> +<td class="nowrap game"><a href="/info/<%= row.title_id %>"><%= row.title_name %></a> <td><%= row.scenario %> -<td><%= row.player_names %> +<td class="names"><%- row.player_names %> <td><%= row.description %> <td class="nowrap"><%= row.mtime %> <% @@ -78,9 +79,9 @@ Your mail address is <%= user.mail %>. <% finished_games.forEach((row) => { %> <tr> <td><%= row.game_id %> -<td class="nowrap"><a href="/info/<%= row.title_id %>"><%= row.title_name %></a> +<td class="nowrap game"><a href="/info/<%= row.title_id %>"><%= row.title_name %></a> <td><%= row.scenario %> -<td><%= row.player_names %> +<td class="names"><%- row.player_names %> <td><%= row.description %> <td class="nowrap"><%= row.mtime %> <td><%= row.result %> diff --git a/views/users.ejs b/views/users.ejs index 526b722..d6e4d4a 100644 --- a/views/users.ejs +++ b/views/users.ejs @@ -10,7 +10,7 @@ td.avatar img{display:block;width:80px;height:80px;} <% userList.forEach((row) => { %> <tr> <td class="avatar"><img src="<%= row.avatar %>"> -<td><a href="/user/<%= row.user_id %>"><%= row.name %></a> +<td><a href="/user/<%= row.name %>"><%= row.name %></a> <td><%= row.ctime %> <td><%= row.atime %> <% }); %> |