web: Move web app to ‘web’ directory.

Ever since we started bundling the app with webpack, there’s been less
and less overlap between our ‘static’ directory (files belonging to
the frontend app) and Django’s interpretation of the ‘static’
directory (files served directly to the web).

Split the app out to its own ‘web’ directory outside of ‘static’, and
remove all the custom collectstatic --ignore rules.  This makes it
much clearer what’s actually being served to the web, and what’s being
bundled by webpack.  It also shrinks the release tarball by 3%.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg
2023-02-22 14:03:47 -08:00
parent be0098146c
commit c1675913a2
866 changed files with 978 additions and 993 deletions

155
web/src/submessage.js Normal file
View File

@@ -0,0 +1,155 @@
import * as blueslip from "./blueslip";
import * as channel from "./channel";
import * as message_store from "./message_store";
import * as widgetize from "./widgetize";
export function get_message_events(message) {
if (message.locally_echoed) {
return undefined;
}
if (!message.submessages) {
return undefined;
}
if (message.submessages.length === 0) {
return undefined;
}
message.submessages.sort((m1, m2) => Number.parseInt(m1.id, 10) - Number.parseInt(m2.id, 10));
const events = message.submessages.map((obj) => ({
sender_id: obj.sender_id,
data: JSON.parse(obj.content),
}));
return events;
}
export function process_submessages(in_opts) {
// This happens in our rendering path, so we try to limit any
// damage that may be triggered by one rogue message.
try {
return do_process_submessages(in_opts);
} catch (error) {
blueslip.error("in process_submessages: " + error.message);
return undefined;
}
}
export function do_process_submessages(in_opts) {
const message_id = in_opts.message_id;
const message = message_store.get(message_id);
if (!message) {
return;
}
const events = get_message_events(message);
if (!events) {
return;
}
if (events[0].sender_id !== message.sender_id) {
blueslip.warn(`User ${events[0].sender_id} tried to hijack message ${message.id}`);
return;
}
const $row = in_opts.$row;
// Right now, our only use of submessages is widgets.
const data = events[0].data;
if (data === undefined) {
return;
}
const widget_type = data.widget_type;
if (widget_type === undefined) {
return;
}
const post_to_server = make_server_callback(message_id);
widgetize.activate({
widget_type,
extra_data: data.extra_data,
events,
$row,
message,
post_to_server,
});
}
export function update_message(submsg) {
const message = message_store.get(submsg.message_id);
if (message === undefined) {
// This is generally not a problem--the server
// can send us events without us having received
// the original message, since the server doesn't
// track that.
return;
}
if (message.submessages === undefined) {
message.submessages = [];
}
const existing = message.submessages.find((sm) => sm.id === submsg.id);
if (existing !== undefined) {
blueslip.warn("Got submessage multiple times: " + submsg.id);
return;
}
message.submessages.push(submsg);
}
export function handle_event(submsg) {
// Update message.submessages in case we haven't actually
// activated the widget yet, so that when the message does
// come in view, the data will be complete.
update_message(submsg);
// Right now, our only use of submessages is widgets.
const msg_type = submsg.msg_type;
if (msg_type !== "widget") {
blueslip.warn("unknown msg_type: " + msg_type);
return;
}
let data;
try {
data = JSON.parse(submsg.content);
} catch {
blueslip.warn("server sent us invalid json in handle_event: " + submsg.content);
return;
}
widgetize.handle_event({
sender_id: submsg.sender_id,
message_id: submsg.message_id,
data,
});
}
export function make_server_callback(message_id) {
return function (opts) {
const url = "/json/submessage";
channel.post({
url,
data: {
message_id,
msg_type: opts.msg_type,
content: JSON.stringify(opts.data),
},
});
};
}