-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(matrix/space): implemented space.board
events
#16
Conversation
Stumbled upon some difficulties here since I wanted to do stuff correct without changing the API later. I chose to separate `post` from `reply` to prevent having a separate `topic` event. Votes for `reply` are calculated through `m.reaction` but since it can form a relation with any event we can't enforce votes on this event type only. I was not sure if we needed an enum for `post` since we might consider having different `body` types in the future such as a poll or media content.
c73b837
to
b0fab96
Compare
Access token is still absent since I'm still not sure how we will store them. Another consideration to make is whether to require `room_id` for replies since we *could* retrieve for the event being replied to and extract it from there.
crates/core/src/events/service.rs
Outdated
pub async fn all_events(&self) -> Result<Vec<LegacyEntity>> { | ||
let statement = " | ||
SELECT | ||
e.event_id, | ||
js.json, | ||
ms.display_name, | ||
ms.avatar_url, | ||
ra.room_alias, | ||
RIGHT(e.event_id, 11) AS slug, | ||
js.json :: json ->> 'origin_server_ts' AS edited_on, | ||
0 AS replies, | ||
FROM | ||
events e | ||
LEFT JOIN event_json js USING(event_id) | ||
LEFT JOIN room_aliases ra USING(room_id) | ||
LEFT JOIN event_relations er ON er.relates_to_id = e.event_id | ||
LEFT JOIN redactions ON redacts = e.event_id | ||
LEFT JOIN membership_state ms ON ms.user_id = e.sender | ||
AND ms.room_id = e.room_id | ||
WHERE | ||
e.origin_server_ts < $1 | ||
AND e.type = 'space.board.post' | ||
AND redacts IS NULL | ||
AND aliases.room_alias IS NOT NULL | ||
"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way to achieve this via API? I would rather avoid querying database directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is possible for Matrix events but our problem is that the response is paginated (see below).
I also decided to avoid plain SQL and go with sea_query
instead as we wanna support SQLite and RocksDB in the future.
https://matrix-org.github.io/synapse/latest/admin_api/rooms.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can use filters and search terms for this perhaps?
crates/core/src/events/service.rs
Outdated
pub async fn all_replies(&self) -> Result<Vec<()>> { | ||
unimplemented!() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please avoid committing unimplemented functions.
crates/core/src/lib.rs
Outdated
@@ -1,15 +1,19 @@ | |||
pub mod account; | |||
pub mod auth; | |||
pub mod db; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Direct database access is not encouraged, unless core contains an owned DB I suggest using the Synapse API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would use SQL Read Ops as last resort, its safer to use API as DAL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No direct database access should be happening.
f9271c6
to
ef21bd9
Compare
Excuses for not writing any tests yet by the way! |
@@ -9,6 +9,7 @@ default-members = ["crates/server"] | |||
resolver = "1" | |||
|
|||
[workspace.dependencies] | |||
assert_matches2 = "0.1.2" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this required?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is used for tests.
See: https://docs.rs/assert_matches2/latest/assert_matches2
let mut tmp = (*self.admin).clone(); | ||
tmp.set_token(access_token.to_string()).map_err(|err| { | ||
tracing::error!(?err, "Failed to set access token"); | ||
Error::Unknown | ||
})?; | ||
|
||
tmp.put_json(path, &body).await.map_err(|err| { | ||
tracing::error!(?err, "Failed to make http request"); | ||
Error::Unknown | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please specify error cause. Context is defined in the API
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you elaborate on context? The first error can only happen when the token is of the wrong format or empty, while the second one can be related to a wrong access token or malformed body.
Returning Error::Unknown
here is not ideal, is that what you want to be changed?
pub async fn send_post<S: AsRef<str>>( | ||
&self, | ||
content: Raw<BoardPostEventContent>, | ||
board_id: S, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
board_id: S, | |
board_id: impl AsRef<str>, |
Given that this is the single param that uses generic value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for giving this a shot!
I see this PR involves many features all at once in different layers of abstraction. I suggest split it into different PRs to address each concern at its own level.
I suggest using API calls over DB conns for DAL as well.
And please add tests, its important code is validated and that we can ensure it doesn't breaks with future changes!
I can see theres many types of events addressed all at once, perhaps adding the event abstraction to matrix crate is a good start for a PR, then introduce one of the event types and finally introduce it to the core logic so its presented (this could be a second PR) at this point testing against matrix and core logic its easy (refer to test crate for examples).
Keep it up!!
let resp = self | ||
.put_json(endpoint, &content, access_token) | ||
.await | ||
.map_err(|err| { | ||
tracing::error!(?err, "Failed to forward custom event"); | ||
Error::Unknown | ||
})?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please map API error codes
let data: CreateEventResponse = resp.json().await.map_err(|err| { | ||
tracing::error!(?err, "Failed deserialize Synapse response"); | ||
Error::Unknown | ||
})?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that API version is pinned this shouldnt happen. Can you add tests for response bodies ad deserialization?
pub const POSTGRES_HOST: &str = "POSTGRES_HOST"; | ||
pub const POSTGRES_USER: &str = "POSTGRES_USER"; | ||
pub const POSTGRES_PASSWORD: &str = "POSTGRES_PASSWORD"; | ||
pub const POSTGRES_DB: &str = "POSTGRES_DB"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DB connection is not recommended. I suggest using API please.
use anyhow::Result; | ||
use ruma_common::serde::Raw; | ||
use ruma_common::{OwnedEventId, OwnedRoomId, TransactionId}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should have CI/CD set up for formatting.
|
||
#[derive(Serialize, Deserialize)] | ||
pub struct CreateEventResponse { | ||
event_id: String, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use newtype please
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you elaborate a bit on why is this called legacy, please?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I already explained this ... it was to keep backward compatibility. Seems like it doesn't matter since it's only making implementation harder than necessary.
let event = Router::new() | ||
.route("/", get(unimplemented)) | ||
.route("/thread", get(unimplemented)) | ||
.route("/replies", get(unimplemented)) | ||
.merge(protected); | ||
|
||
let events = Router::new() | ||
.route("/", get(unimplemented)) | ||
.route("/:room", get(unimplemented)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid pushing unimplemented code please.
let event = Router::new() | |
.route("/", get(unimplemented)) | |
.route("/thread", get(unimplemented)) | |
.route("/replies", get(unimplemented)) | |
.merge(protected); | |
let events = Router::new() | |
.route("/", get(unimplemented)) | |
.route("/:room", get(unimplemented)); |
Stumbled upon some difficulties here since I wanted to do stuff correct without changing the API later.
I chose to separate
post
fromreply
to prevent having a separatetopic
event. Votes forreply
are calculated throughm.reaction
but since it can form a relation with any event we can't enforce votes on this event type only.I was not sure if we needed an enum for
post
since we might consider having differentbody
types in the future such as a poll or media content.