Skip to content

Commit

Permalink
feat: impl create discord message endpoint (#33)
Browse files Browse the repository at this point in the history
Implement create discord message endpoint in this PR. The left unsolved issue is #32. We need to rethink how and when we will help user to build the JSON data.
  • Loading branch information
EiffelFly authored Feb 15, 2023
1 parent 279ac3d commit 1d144ff
Show file tree
Hide file tree
Showing 7 changed files with 314 additions and 14 deletions.
12 changes: 12 additions & 0 deletions packages/server/proto/third_party/v1alpha/discord_service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ service DiscordService {
rpc DeleteDiscordMessage(DeleteDiscordMessageRequest) returns (DeleteDiscordMessageResponse);
rpc GetDiscordMessage(GetDiscordMessageRequest) returns (GetDiscordMessageResponse);
rpc ListDiscordMessage(ListDiscordMessageRequest) returns (ListDiscordMessageResponse);
rpc CreateDiscordThread(CreateDiscordThreadRequest) returns (CreateDiscordThreadResponse);
}

message CreateDiscordMessageRequest {
Expand Down Expand Up @@ -45,4 +46,15 @@ message ListDiscordMessageRequest {
message ListDiscordMessageResponse {
repeated third_party.v1alpha.DiscordMessage discord_messages = 1;
int32 size = 2;
}

message CreateDiscordThreadRequest {
string thread_id = 1;
string markdown_content = 2;
string url = 3;
int64 created_timestamp_at_discord = 4;
}

message CreateDiscordThreadResponse {
third_party.v1alpha.DiscordThread discord_thread = 1;
}
114 changes: 114 additions & 0 deletions packages/server/src/db/model/third_party/discord.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,120 @@ pub struct DiscordThread {
pub created_timestamp_at_discord: String,
}

#[derive(Debug)]
pub struct CreateDiscordThreadPayload {
pub thread_id: String,
pub markdown_content: String,
pub url: String,
pub created_timestamp_at_discord: Datetime,
}

impl DiscordThread {
pub async fn create(
client: Client,
payload: &CreateDiscordThreadPayload,
) -> Result<Self, anyhow::Error> {
let create_url_payload = db_curioucity::CreateUrlPayload {
url: payload.url.clone(),
resource_type: db_curioucity::ResourceType::DiscordThread,
};

match FullUrl::create(&client, &create_url_payload).await {
Ok(_) => {}
Err(error) => {
println!("Error when create url: {:?}", error);
bail!("Error when create url: {}", error)
}
}

let create_discord_thread_query = "select (
insert DiscordThread {
kind := 'DISCORD_THREAD',
thread_id := <str>$0,
markdown_content := <str>$1,
created_timestamp_at_discord := <datetime>$2,
created_timestamp_at_curioucity := <datetime>$3,
url := (select Url filter .url = <str>$4),
full_messages_json := to_json(<str>$5),
}
) {
id,
thread_id,
kind,
created_timestamp_at_discord,
created_timestamp_at_curioucity,
markdown_content,
full_messages_json,
url: {
id,
url,
references,
resource_type,
created_timestamp_at_curioucity,
},
tags: {
id,
name
},
messages: {
id
}
};";

let created_timestamp_at_curioucity =
match get_edgedb_timestamp_from_2000_micros(Utc::now().timestamp_micros()) {
Ok(time) => time,
Err(error) => {
println!("Time is out of range: {:?}", error);
bail!("{}", error)
}
};

// We need to implement this json object in the future
let mock_json_value = serde_json::json!({"key": "value"}).to_string();

let response_json = match client
.query_json(
&create_discord_thread_query,
&(
&payload.thread_id,
&payload.markdown_content,
&payload.created_timestamp_at_discord,
&created_timestamp_at_curioucity,
&payload.url,
&mock_json_value,
),
)
.await
{
Ok(json) => json,
Err(error) => {
println!("Error: {:?}", error);
bail!("{}", error)
}
};

let discord_threads =
match serde_json::from_str::<Vec<DiscordThread>>(response_json.as_ref()) {
Ok(result) => result,
Err(error) => {
println!("Deserialize Error: {}", error);
bail!("Deserialize Error: {}", error)
}
};

let discord_thread = match discord_threads.into_iter().nth(0) {
Some(result) => result,
None => {
println!("Deserialize Error, deserialized element not found");
bail!("Deserialize Error, deserialized element not found")
}
};

Ok(discord_thread)
}
}

impl From<DiscordThread> for pb_third_party::DiscordThread {
fn from(value: DiscordThread) -> Self {
transform_discord_thread_to_pb(&value)
Expand Down
54 changes: 54 additions & 0 deletions packages/server/src/grpc_handler/third_party/discord.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,60 @@ pub struct GrpcDiscordServiceImpl {}

#[tonic::async_trait]
impl pb_third_party::discord_service_server::DiscordService for GrpcDiscordServiceImpl {
async fn create_discord_thread(
&self,
req: Request<pb_third_party::CreateDiscordThreadRequest>,
) -> Result<Response<pb_third_party::CreateDiscordThreadResponse>, Status> {
let client = match edgedb_tokio::create_client().await {
Ok(client) => client,
Err(error) => {
return Err(Status::internal(format!(
"Something went wrong when access database: {}",
error
)))
}
};

let req_ref = req.get_ref();

// Discord store their timestamp in seconds, but we need to convert it to micros seconds
let edgedb_datetime = match get_edgedb_timestamp_from_2000_micros(
req_ref.created_timestamp_at_discord * 1000000,
) {
Ok(datetime) => datetime,
Err(error) => {
return Err(Status::internal(format!(
"Something went wrong when parse discord int timestamp: {}",
error
)))
}
};

let payload = db_third_party::discord::CreateDiscordThreadPayload {
thread_id: req_ref.thread_id.clone(),
created_timestamp_at_discord: edgedb_datetime,
markdown_content: req_ref.markdown_content.clone(),
url: req_ref.url.clone(),
};

let discord_thread =
match db_third_party::discord::DiscordThread::create(client, &payload).await {
Ok(discord_message) => discord_message,
Err(error) => {
return Err(Status::internal(format!(
"Something went wrong when create discord message: {}",
error
)))
}
};

let resp = pb_third_party::CreateDiscordThreadResponse {
discord_thread: Some(discord_thread.as_pb_type()),
};

Ok(Response::new(resp))
}

async fn create_discord_message(
&self,
req: Request<pb_third_party::CreateDiscordMessageRequest>,
Expand Down
7 changes: 6 additions & 1 deletion packages/server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ use rest_handler::curioucity::{
create_tag, create_url, delete_tag, delete_url, get_tag, get_url, list_tag, list_url,
};
use rest_handler::third_party::discord::{
create_discord_message, delete_discord_message, get_discord_message, list_discord_message,
create_discord_message, create_discord_thread, delete_discord_message, get_discord_message,
list_discord_message,
};

use tonic::transport::Server;
Expand All @@ -43,6 +44,10 @@ async fn main() {
.route("/tags/:name", axum::routing::delete(delete_tag))
.route("/tags/:name", axum::routing::get(get_tag))
.route("/tags", axum::routing::get(list_tag))
.route(
"/discord/threads/create",
axum::routing::post(create_discord_thread),
)
.route(
"/discord/messages/create",
axum::routing::post(create_discord_message),
Expand Down
59 changes: 58 additions & 1 deletion packages/server/src/rest_handler/third_party/discord.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,63 @@ use axum::extract::Path;
use axum::response::Response;
use axum::{http::StatusCode, response::IntoResponse, Json};

pub async fn create_discord_thread(
payload: Json<pb_third_party::CreateDiscordThreadRequest>,
) -> Result<impl IntoResponse, Response> {
let client = match edgedb_tokio::create_client().await {
Ok(result) => result,
Err(error) => {
return Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Something went wrong when access database: {}", error),
)
.into_response())
}
};

// Discord store their timestamp in seconds, but we need to convert it to micros seconds
let edgedb_datetime =
match get_edgedb_timestamp_from_2000_micros(payload.created_timestamp_at_discord * 1000000)
{
Ok(result) => result,
Err(error) => {
return Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!(
"Something went wrong when parse discord int timestamp: {}",
error
),
)
.into_response())
}
};

let payload = db_third_party::discord::CreateDiscordThreadPayload {
thread_id: payload.thread_id.clone(),
created_timestamp_at_discord: edgedb_datetime,
markdown_content: payload.markdown_content.clone(),
url: payload.url.clone(),
};

let discord_thread =
match db_third_party::discord::DiscordThread::create(client, &payload).await {
Ok(result) => result,
Err(error) => {
return Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Something went wrong when create discord thread: {}", error),
)
.into_response())
}
};

let resp = pb_third_party::CreateDiscordThreadResponse {
discord_thread: Some(discord_thread.as_pb_type()),
};

Ok((StatusCode::CREATED, Json(resp)))
}

pub async fn create_discord_message(
payload: Json<pb_third_party::CreateDiscordMessageRequest>,
) -> Result<impl IntoResponse, Response> {
Expand Down Expand Up @@ -52,7 +109,7 @@ pub async fn create_discord_message(
return Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!(
"Something went wrong when create discord_message: {}",
"Something went wrong when create discord message: {}",
error
),
)
Expand Down
57 changes: 57 additions & 0 deletions tests/api/discord.js
Original file line number Diff line number Diff line change
Expand Up @@ -329,3 +329,60 @@ export const listDiscordMessage = () => {
}
});
};

export const createDiscordThread = () => {
group("Disocrd - Should create discord thread", () => {
let discordThreadId = `${Math.floor(Math.random() * 100000000)}`;

let createDiscordThreadPayload = {
thread_id: discordThreadId,
markdown_content: "Hi i am here",
url: `https://discord.com/id/${Math.floor(Math.random() * 100000000)}`,
created_timestamp_at_discord: 1675220675,
};

let headers = {
"Content-Type": "application/json",
};

check(
http.request(
"POST",
`${API_HOST}/discord/threads/create`,
JSON.stringify(createDiscordThreadPayload),
{
headers,
}
),
{
"createDiscordThread - POST /discord/threads/create - response status should be 201":
(r) => r.status === 201,
"createDiscordThread - POST /discord/threads/create - response body should have id":
(r) =>
typeof r.json().discord_thread.id !== undefined &&
r.json().discord_thread.id !== null,
"createDiscordThread - POST /discord/threads/create - response body should have correct thread_id":
(r) =>
r.json().discord_thread.thread_id ===
createDiscordThreadPayload.thread_id.toString(),
"createDiscordThread - POST /discord/threads/create - response body should have correct markdown content":
(r) =>
r.json().discord_thread.markdown_content ===
createDiscordThreadPayload.markdown_content,
"createDiscordThread - POST /discord/threads/create - response body should have correct url":
(r) =>
r.json().discord_thread.url.url === createDiscordThreadPayload.url,
"createDiscordThread - POST /discord/threads/create - response body should have correct created_timestamp_at_discord":
(r) =>
Date.parse(r.json().discord_thread.created_timestamp_at_discord) /
1000 ===
createDiscordThreadPayload.created_timestamp_at_discord,
"createDiscordThread - POST /discord/threads/create - response body should have created_timestamp_at_curioucity":
(r) =>
typeof r.json().discord_thread.created_timestamp_at_curioucity !==
"undefined" &&
r.json().discord_thread.created_timestamp_at_curioucity !== null,
}
);
});
};
25 changes: 13 additions & 12 deletions tests/api/rest.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,19 @@ export const options = {};
export const API_HOST = "http://localhost:8080";

const main = () => {
urlServices.createUrl();
urlServices.deleteUrl();
urlServices.getUrl();
urlServices.listUrl();
tagServices.createTag();
tagServices.deleteTag();
tagServices.getTag();
tagServices.listTag();
discordServices.createDiscordMessage();
discordServices.deleteDiscordMessage();
discordServices.getDiscordMessage();
discordServices.listDiscordMessage();
// urlServices.createUrl();
// urlServices.deleteUrl();
// urlServices.getUrl();
// urlServices.listUrl();
// tagServices.createTag();
// tagServices.deleteTag();
// tagServices.getTag();
// tagServices.listTag();
// discordServices.createDiscordMessage();
// discordServices.deleteDiscordMessage();
// discordServices.getDiscordMessage();
// discordServices.listDiscordMessage();
discordServices.createDiscordThread();
};

export default main;

0 comments on commit 1d144ff

Please sign in to comment.