Skip to content

Commit 09b6859

Browse files
committed
doneso
1 parent a6920bd commit 09b6859

File tree

15 files changed

+359
-42
lines changed

15 files changed

+359
-42
lines changed

Cargo.lock

+4-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

trackscape-discord-api/src/controllers/clan_controller.rs

+45-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use actix_web::{get, web, Error, HttpResponse, Scope};
22
use log::{error, info};
33
use serde::{Deserialize, Serialize};
44
use std::str::FromStr;
5-
use tokio::time::sleep;
65
use trackscape_discord_shared::database::clan_mate_collection_log_totals::ClanMateCollectionLogTotals;
76
use trackscape_discord_shared::database::clan_mates::{ClanMateModel, ClanMates};
87
use trackscape_discord_shared::database::BotMongoDb;
@@ -106,7 +105,6 @@ async fn collection_log(
106105
mongodb: Data<BotMongoDb>,
107106
path: web::Path<(String,)>,
108107
) -> Result<HttpResponse, Error> {
109-
sleep(std::time::Duration::from_secs(1)).await;
110108
let id = path.into_inner().0;
111109
let possible_parsed_id = bson::oid::ObjectId::from_str(id.as_str());
112110
let id = match possible_parsed_id {
@@ -148,9 +146,54 @@ async fn collection_log(
148146
}
149147
}
150148

149+
#[derive(Deserialize)]
150+
struct BroadcastRequest {
151+
id: String,
152+
limit: i64,
153+
}
154+
155+
#[get("/{id}/broadcasts/{limit}")]
156+
async fn broadcasts(
157+
mongodb: Data<BotMongoDb>,
158+
path: web::Path<BroadcastRequest>,
159+
) -> Result<HttpResponse, Error> {
160+
let possible_parsed_id = bson::oid::ObjectId::from_str(path.id.as_str());
161+
let id = match possible_parsed_id {
162+
Ok(parsed_id) => parsed_id,
163+
Err(_) => {
164+
return Ok(HttpResponse::BadRequest().body("Invalid id format."));
165+
}
166+
};
167+
let registered_guild_query = mongodb.guilds.get_by_id(id).await;
168+
match registered_guild_query {
169+
Ok(possible_guild) => match possible_guild {
170+
Some(guild) => {
171+
let limit_to_use = if path.limit > 100 { 100 } else { path.limit };
172+
let broadcasts = mongodb
173+
.broadcasts
174+
.get_latest_broadcasts(guild.guild_id, limit_to_use)
175+
.await;
176+
match broadcasts {
177+
Ok(broadcasts) => Ok(HttpResponse::Ok().json(broadcasts)),
178+
Err(err) => {
179+
error!("Failed to get broadcasts: {}", err);
180+
Ok(HttpResponse::BadRequest().body("There was an issue with the request"))
181+
}
182+
}
183+
}
184+
None => Ok(HttpResponse::BadRequest().body("There is not a clan with that id")),
185+
},
186+
Err(err) => {
187+
error!("Failed to get clan by id: {}", err);
188+
Ok(HttpResponse::BadRequest().body("There was an issue with the request"))
189+
}
190+
}
191+
}
192+
151193
pub fn clan_controller() -> Scope {
152194
web::scope("/clans")
153195
.service(list_clans)
154196
.service(detail)
155197
.service(collection_log)
198+
.service(broadcasts)
156199
}

trackscape-discord-shared/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ edition = "2021"
77

88
[dependencies]
99
async-recursion = "1.0.5"
10+
bson = { version = "2.10.0", features = ["chrono-0_4"] }
1011
tracing = "0.1.37"
1112
num-format = "0.4.4"
1213
futures = "0.3.28"

trackscape-discord-shared/src/database/broadcasts.rs

+25-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use crate::database::BroadcastsDb;
22
use crate::osrs_broadcast_handler::BroadcastMessageToDiscord;
3+
use bson::DateTime;
4+
use futures::TryStreamExt;
35
use mockall::predicate::*;
4-
use mongodb::bson::{doc, DateTime};
6+
use mongodb::bson::doc;
57
use mongodb::{bson, Database};
68
use serde::{Deserialize, Serialize};
79

@@ -11,7 +13,11 @@ pub struct BroadcastModel {
1113
pub id: bson::oid::ObjectId,
1214
pub guild_id: u64,
1315
pub broadcast: BroadcastMessageToDiscord,
14-
pub created_at: Option<DateTime>,
16+
#[serde(serialize_with = "bson::serde_helpers::serialize_bson_datetime_as_rfc3339_string")]
17+
#[serde(
18+
deserialize_with = "bson::serde_helpers::deserialize_bson_datetime_from_rfc3339_string"
19+
)]
20+
pub created_at: DateTime,
1521
}
1622

1723
impl BroadcastsDb {
@@ -30,11 +36,27 @@ impl BroadcastsDb {
3036
id: bson::oid::ObjectId::new(),
3137
guild_id,
3238
broadcast,
33-
created_at: Some(DateTime::now()),
39+
created_at: DateTime::now(),
3440
};
3541
collection.insert_one(model, None).await?;
3642
Ok(())
3743
}
44+
45+
pub async fn get_latest_broadcasts(
46+
&self,
47+
guild_id: u64,
48+
limit: i64,
49+
) -> Result<Vec<BroadcastModel>, anyhow::Error> {
50+
let collection = self.db.collection(Self::COLLECTION_NAME);
51+
let filter = doc! { "guild_id": bson::to_bson(&guild_id).unwrap() };
52+
let options = mongodb::options::FindOptions::builder()
53+
.sort(doc! { "created_at": -1 })
54+
.limit(limit)
55+
.build();
56+
let cursor = collection.find(filter, options).await?;
57+
let broadcasts: Vec<BroadcastModel> = cursor.try_collect().await?;
58+
Ok(broadcasts)
59+
}
3860
}
3961

4062
impl BroadcastsDb {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<script setup lang="ts">
2+
import type { Broadcast } from '@/services/TrackscapeApiTypes'
3+
import { type PropType, ref } from 'vue'
4+
5+
const props = defineProps({
6+
broadcast: {
7+
type: Object as PropType<Broadcast>,
8+
required: true
9+
}
10+
})
11+
12+
</script>
13+
14+
<template>
15+
<div class="p-2 shadow-xl bg-base-100">
16+
<div class="flex items-center gap-x-7">
17+
<div class="flex items-center">
18+
<img v-if="props.broadcast.broadcast.icon_url !== null"
19+
class="w-10 h-10 rounded-full object-contain mr-1"
20+
:src="props.broadcast.broadcast.icon_url"
21+
onerror="this.src = '/src/assets/img/Trackscape_Logo_icon.png'"
22+
alt=""
23+
/>
24+
25+
<div>
26+
<p class="text-md font-bold">{{ props.broadcast.broadcast.title }}</p>
27+
<p class="text-sm text-gray-500">{{ props.broadcast.created_at }}</p>
28+
</div>
29+
</div>
30+
</div>
31+
<div class="mt-1">
32+
<p>{{ props.broadcast.broadcast.message }}</p>
33+
</div>
34+
</div>
35+
</template>
36+
37+
<style scoped>
38+
39+
</style>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<script setup lang="ts">
2+
import BroadcastItem from '@/components/BroadcastItem.vue'
3+
import { ref } from 'vue'
4+
import type { Broadcast } from '@/services/TrackscapeApiTypes'
5+
import TrackscapeApiClient from '@/services/TrackscapeApiClient'
6+
7+
let broadcasts = ref<Broadcast[]>()
8+
let loading = ref(true)
9+
let props = defineProps({
10+
clanId: {
11+
type: String,
12+
required: true
13+
},
14+
limit: {
15+
type: Number,
16+
required: false,
17+
default: 10
18+
},
19+
showHeader: {
20+
type: Boolean,
21+
required: false,
22+
default: true
23+
}
24+
})
25+
26+
27+
let client = new TrackscapeApiClient(import.meta.env.VITE_API_BASE_URL)
28+
29+
client.getBroadcasts(props.clanId, props.limit).then((broadcastsResult) => {
30+
broadcastsResult.forEach((broadcast) => {
31+
broadcast.created_at = new Date(broadcast.created_at).toLocaleString()
32+
broadcast.broadcast.title = broadcast.broadcast.title.replace(/:.*:/, '')
33+
})
34+
broadcasts.value = broadcastsResult
35+
loading.value = false
36+
})
37+
38+
</script>
39+
40+
<template>
41+
<TransitionGroup name="slide-fade">
42+
43+
<div v-if="loading">
44+
<div class="flex items-center gap-x-2">
45+
</div>
46+
<div class="mt-2">
47+
<div v-for="index in 10"
48+
:key="index"
49+
class="p-2 shadow-xl bg-base-100">
50+
<div class="p-2 shadow-xl bg-base-100">
51+
<div class="flex items-center ">
52+
<div class="flex items-center">
53+
<div class="skeleton w-10 h-10 rounded-full shrink-0"></div>
54+
<div class="flex flex-col gap-1">
55+
<div class="skeleton h-6 w-28"></div>
56+
<div class="skeleton h-4 w-28"></div>
57+
</div>
58+
</div>
59+
</div>
60+
<div class="mt-1 flex flex-col gap-1">
61+
<div class="skeleton h-4 w-3/4"></div>
62+
<div class="skeleton h-4 w-3/4"></div>
63+
</div>
64+
</div>
65+
</div>
66+
</div>
67+
</div>
68+
69+
<div v-else>
70+
<div class="flex items-center gap-x-2">
71+
<div v-if="props.showHeader"
72+
class="flex items-center">
73+
<div>
74+
<p class="text-lg font-bold">Recent Broadcasts</p>
75+
</div>
76+
</div>
77+
</div>
78+
<div class="mt-2">
79+
<div v-for="broadcast in broadcasts"
80+
:key="broadcast.id"
81+
class="p-5 shadow-xl bg-base-100">
82+
<BroadcastItem :broadcast="broadcast" />
83+
</div>
84+
</div>
85+
</div>
86+
</TransitionGroup>
87+
88+
89+
</template>
90+
91+
<style scoped>
92+
.slide-fade-enter-active {
93+
transition: all 0.1s ease-in;
94+
}
95+
96+
.slide-fade-leave-active {
97+
transition: all 0.3s cubic-bezier(1, 0.5, 0.8, 1);
98+
}
99+
100+
.slide-fade-enter-from,
101+
.slide-fade-leave-to {
102+
transform: translateX(-20px);
103+
opacity: 0;
104+
}
105+
</style>

trackscape-discord-ui/src/router/clans.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,18 @@ export default [
1414
{
1515
path: "",
1616
name: "members",
17-
component: () => import('@/views/clans/clan/MembersView.vue'),
17+
component: () => import('@/views/clans/clan/subviews/MembersView.vue'),
1818

1919
},
2020
{
2121
path: "collectionlog",
2222
name: "collection-log",
23-
component: () => import('@/views/clans/clan/CollectionLogLeaderboardView.vue'),
23+
component: () => import('@/views/clans/clan/subviews/CollectionLogLeaderboardView.vue'),
24+
},
25+
{
26+
path: "broadcasts",
27+
name: "broadcasts",
28+
component: () => import('@/views/clans/clan/subviews/RecentBroadcastsView.vue'),
2429
}
2530
]
2631

trackscape-discord-ui/src/services/TrackscapeApiClient.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import type {BotInfo, Clan, ClanDetail, ClanMateCollectionLogTotalsView} from "@/services/TrackscapeApiTypes";
1+
import type {
2+
BotInfo,
3+
Broadcast,
4+
Clan,
5+
ClanDetail,
6+
ClanMateCollectionLogTotalsView
7+
} from '@/services/TrackscapeApiTypes'
28

39
export default class TrackscapeApiClient {
410

@@ -29,5 +35,9 @@ export default class TrackscapeApiClient {
2935
return this.get<ClanMateCollectionLogTotalsView[]>(`/clans/${clanId}/collection-log`);
3036
}
3137

38+
public async getBroadcasts(clanID: string, limit: number): Promise<Broadcast[]> {
39+
return this.get<Broadcast[]>(`/clans/${clanID}/broadcasts/${limit}`);
40+
}
41+
3242
}
3343

0 commit comments

Comments
 (0)