mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
feat(referrals): 添加邀请返利和注册确认功能
This commit is contained in:
@@ -7,7 +7,7 @@ use tracing::info;
|
||||
// Generated by build.rs from schema/bootstrap/postgres.
|
||||
pub(crate) static EMPTY_DATABASE_SNAPSHOT_SQL: &str =
|
||||
include_str!(concat!(env!("OUT_DIR"), "/empty_database_snapshot.sql"));
|
||||
pub(crate) const EMPTY_DATABASE_SNAPSHOT_CUTOFF_VERSION: i64 = 20260515000000;
|
||||
pub(crate) const EMPTY_DATABASE_SNAPSHOT_CUTOFF_VERSION: i64 = 20260516000000;
|
||||
|
||||
const PUBLIC_BASE_TABLE_COUNT_SQL: &str = r#"
|
||||
SELECT COUNT(*)::BIGINT
|
||||
|
||||
@@ -305,6 +305,7 @@ fn empty_database_snapshot_covers_current_cutoff_versions() {
|
||||
20260512090000,
|
||||
20260512110000,
|
||||
20260515000000,
|
||||
20260516000000,
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -587,6 +588,7 @@ fn mysql_and_sqlite_migrations_include_enabled_incrementals() {
|
||||
20260512000000,
|
||||
20260512090000,
|
||||
20260512110000,
|
||||
20260516000000,
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -603,6 +605,7 @@ fn mysql_and_sqlite_migrations_include_enabled_incrementals() {
|
||||
20260512000000,
|
||||
20260512090000,
|
||||
20260512110000,
|
||||
20260516000000,
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -1119,6 +1122,7 @@ fn pending_migrations_from_applied_skips_versions_already_applied() {
|
||||
20260512090000,
|
||||
20260512110000,
|
||||
20260515000000,
|
||||
20260516000000,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -135,6 +135,48 @@ impl AnnouncementReadRepository for InMemoryAnnouncementReadRepository {
|
||||
|
||||
Ok(total)
|
||||
}
|
||||
|
||||
async fn list_required_unread_active_announcements(
|
||||
&self,
|
||||
user_id: &str,
|
||||
now_unix_secs: u64,
|
||||
limit: usize,
|
||||
) -> Result<Vec<StoredAnnouncement>, DataLayerError> {
|
||||
let announcements = self
|
||||
.announcements
|
||||
.read()
|
||||
.expect("announcement repository lock");
|
||||
let reads = self
|
||||
.announcement_reads
|
||||
.read()
|
||||
.expect("announcement reads repository lock");
|
||||
|
||||
let mut items = announcements
|
||||
.iter()
|
||||
.filter(|announcement| {
|
||||
announcement.requires_ack
|
||||
&& announcement.is_active
|
||||
&& announcement
|
||||
.start_time_unix_secs
|
||||
.is_none_or(|value| value <= now_unix_secs)
|
||||
&& announcement
|
||||
.end_time_unix_secs
|
||||
.is_none_or(|value| value >= now_unix_secs)
|
||||
&& !reads.contains(&(user_id.to_string(), announcement.id.clone()))
|
||||
})
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
items.sort_by(|left, right| {
|
||||
right
|
||||
.is_pinned
|
||||
.cmp(&left.is_pinned)
|
||||
.then_with(|| right.priority.cmp(&left.priority))
|
||||
.then_with(|| right.created_at_unix_ms.cmp(&left.created_at_unix_ms))
|
||||
.then_with(|| left.id.cmp(&right.id))
|
||||
});
|
||||
items.truncate(limit);
|
||||
Ok(items)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -153,6 +195,7 @@ impl AnnouncementWriteRepository for InMemoryAnnouncementReadRepository {
|
||||
record.priority,
|
||||
true,
|
||||
record.is_pinned,
|
||||
record.requires_ack,
|
||||
Some(record.author_id),
|
||||
None,
|
||||
record.start_time_unix_secs.map(|value| value as i64),
|
||||
@@ -201,6 +244,9 @@ impl AnnouncementWriteRepository for InMemoryAnnouncementReadRepository {
|
||||
if let Some(is_pinned) = record.is_pinned {
|
||||
announcement.is_pinned = is_pinned;
|
||||
}
|
||||
if let Some(requires_ack) = record.requires_ack {
|
||||
announcement.requires_ack = requires_ack;
|
||||
}
|
||||
if let Some(start_time_unix_secs) = record.start_time_unix_secs {
|
||||
announcement.start_time_unix_secs = Some(start_time_unix_secs);
|
||||
}
|
||||
@@ -261,6 +307,7 @@ mod tests {
|
||||
10,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
Some("admin-1".to_string()),
|
||||
Some("admin".to_string()),
|
||||
None,
|
||||
@@ -291,6 +338,7 @@ mod tests {
|
||||
kind: "maintenance".to_string(),
|
||||
priority: 10,
|
||||
is_pinned: true,
|
||||
requires_ack: false,
|
||||
author_id: "admin-1".to_string(),
|
||||
start_time_unix_secs: None,
|
||||
end_time_unix_secs: None,
|
||||
@@ -308,6 +356,7 @@ mod tests {
|
||||
priority: Some(99),
|
||||
is_active: Some(false),
|
||||
is_pinned: Some(false),
|
||||
requires_ack: Some(true),
|
||||
start_time_unix_secs: None,
|
||||
end_time_unix_secs: None,
|
||||
})
|
||||
@@ -337,6 +386,7 @@ mod tests {
|
||||
10,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
Some("admin-1".to_string()),
|
||||
Some("admin".to_string()),
|
||||
None,
|
||||
@@ -353,6 +403,7 @@ mod tests {
|
||||
5,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
Some("admin-1".to_string()),
|
||||
Some("admin".to_string()),
|
||||
None,
|
||||
|
||||
@@ -18,6 +18,7 @@ SELECT
|
||||
a.priority,
|
||||
a.is_active,
|
||||
a.is_pinned,
|
||||
a.requires_ack,
|
||||
a.author_id,
|
||||
u.username AS author_username,
|
||||
a.start_time AS start_time_unix_secs,
|
||||
@@ -144,6 +145,39 @@ WHERE a.is_active = 1
|
||||
.map_sql_err()?;
|
||||
Ok(row.try_get::<i64, _>("total").map_sql_err()?.max(0) as u64)
|
||||
}
|
||||
|
||||
async fn list_required_unread_active_announcements(
|
||||
&self,
|
||||
user_id: &str,
|
||||
now_unix_secs: u64,
|
||||
limit: usize,
|
||||
) -> Result<Vec<StoredAnnouncement>, DataLayerError> {
|
||||
let rows = sqlx::query(&format!(
|
||||
r#"
|
||||
{ANNOUNCEMENT_SELECT}
|
||||
WHERE a.is_active = 1
|
||||
AND a.requires_ack = 1
|
||||
AND (a.start_time IS NULL OR a.start_time <= ?)
|
||||
AND (a.end_time IS NULL OR a.end_time >= ?)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM announcement_reads r
|
||||
WHERE r.user_id = ?
|
||||
AND r.announcement_id = a.id
|
||||
)
|
||||
ORDER BY a.is_pinned DESC, a.priority DESC, a.created_at DESC, a.id ASC
|
||||
LIMIT ?
|
||||
"#
|
||||
))
|
||||
.bind(now_unix_secs as i64)
|
||||
.bind(now_unix_secs as i64)
|
||||
.bind(user_id)
|
||||
.bind(limit as i64)
|
||||
.fetch_all(&self.pool)
|
||||
.await
|
||||
.map_sql_err()?;
|
||||
rows.iter().map(map_announcement_row).collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -159,9 +193,9 @@ impl AnnouncementWriteRepository for MysqlAnnouncementRepository {
|
||||
r#"
|
||||
INSERT INTO announcements (
|
||||
id, title, content, `type`, priority, author_id, is_active, is_pinned,
|
||||
start_time, end_time, created_at, updated_at
|
||||
requires_ack, start_time, end_time, created_at, updated_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?)
|
||||
VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?)
|
||||
"#,
|
||||
)
|
||||
.bind(&id)
|
||||
@@ -171,6 +205,7 @@ VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?)
|
||||
.bind(record.priority)
|
||||
.bind(record.author_id)
|
||||
.bind(record.is_pinned)
|
||||
.bind(record.requires_ack)
|
||||
.bind(optional_i64_from_u64(
|
||||
record.start_time_unix_secs,
|
||||
"announcements.start_time",
|
||||
@@ -204,6 +239,7 @@ SET title = COALESCE(?, title),
|
||||
priority = COALESCE(?, priority),
|
||||
is_active = COALESCE(?, is_active),
|
||||
is_pinned = COALESCE(?, is_pinned),
|
||||
requires_ack = COALESCE(?, requires_ack),
|
||||
start_time = COALESCE(?, start_time),
|
||||
end_time = COALESCE(?, end_time),
|
||||
updated_at = ?
|
||||
@@ -216,6 +252,7 @@ WHERE id = ?
|
||||
.bind(record.priority)
|
||||
.bind(record.is_active)
|
||||
.bind(record.is_pinned)
|
||||
.bind(record.requires_ack)
|
||||
.bind(optional_i64_from_u64(
|
||||
record.start_time_unix_secs,
|
||||
"announcements.start_time",
|
||||
@@ -303,6 +340,7 @@ fn map_announcement_row(row: &MySqlRow) -> Result<StoredAnnouncement, DataLayerE
|
||||
row.try_get("priority").map_sql_err()?,
|
||||
row.try_get("is_active").map_sql_err()?,
|
||||
row.try_get("is_pinned").map_sql_err()?,
|
||||
row.try_get("requires_ack").map_sql_err()?,
|
||||
row.try_get("author_id").map_sql_err()?,
|
||||
row.try_get("author_username").map_sql_err()?,
|
||||
row.try_get("start_time_unix_secs").map_sql_err()?,
|
||||
|
||||
@@ -18,6 +18,7 @@ SELECT
|
||||
a.priority,
|
||||
a.is_active,
|
||||
a.is_pinned,
|
||||
a.requires_ack,
|
||||
a.author_id,
|
||||
u.username AS author_username,
|
||||
EXTRACT(EPOCH FROM a.start_time)::bigint AS start_time_unix_secs,
|
||||
@@ -39,6 +40,7 @@ SELECT
|
||||
a.priority,
|
||||
a.is_active,
|
||||
a.is_pinned,
|
||||
a.requires_ack,
|
||||
a.author_id,
|
||||
u.username AS author_username,
|
||||
EXTRACT(EPOCH FROM a.start_time)::bigint AS start_time_unix_secs,
|
||||
@@ -85,6 +87,38 @@ WHERE a.is_active = TRUE
|
||||
)
|
||||
"#;
|
||||
|
||||
const LIST_REQUIRED_UNREAD_ACTIVE_ANNOUNCEMENTS_SQL: &str = r#"
|
||||
SELECT
|
||||
a.id,
|
||||
a.title,
|
||||
a.content,
|
||||
a.type,
|
||||
a.priority,
|
||||
a.is_active,
|
||||
a.is_pinned,
|
||||
a.requires_ack,
|
||||
a.author_id,
|
||||
u.username AS author_username,
|
||||
EXTRACT(EPOCH FROM a.start_time)::bigint AS start_time_unix_secs,
|
||||
EXTRACT(EPOCH FROM a.end_time)::bigint AS end_time_unix_secs,
|
||||
EXTRACT(EPOCH FROM a.created_at)::bigint AS created_at_unix_ms,
|
||||
EXTRACT(EPOCH FROM a.updated_at)::bigint AS updated_at_unix_secs
|
||||
FROM announcements a
|
||||
LEFT JOIN users u ON u.id = a.author_id
|
||||
WHERE a.is_active = TRUE
|
||||
AND a.requires_ack = TRUE
|
||||
AND (a.start_time IS NULL OR a.start_time <= TO_TIMESTAMP($2::double precision))
|
||||
AND (a.end_time IS NULL OR a.end_time >= TO_TIMESTAMP($2::double precision))
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM announcement_reads r
|
||||
WHERE r.user_id = $1
|
||||
AND r.announcement_id = a.id
|
||||
)
|
||||
ORDER BY a.is_pinned DESC, a.priority DESC, a.created_at DESC, a.id ASC
|
||||
LIMIT $3
|
||||
"#;
|
||||
|
||||
const CREATE_ANNOUNCEMENT_SQL: &str = r#"
|
||||
INSERT INTO announcements (
|
||||
id,
|
||||
@@ -95,6 +129,7 @@ INSERT INTO announcements (
|
||||
author_id,
|
||||
is_active,
|
||||
is_pinned,
|
||||
requires_ack,
|
||||
start_time,
|
||||
end_time,
|
||||
created_at,
|
||||
@@ -111,6 +146,7 @@ VALUES (
|
||||
$7,
|
||||
$8,
|
||||
$9,
|
||||
$10,
|
||||
NOW(),
|
||||
NOW()
|
||||
)
|
||||
@@ -122,6 +158,7 @@ RETURNING
|
||||
priority,
|
||||
is_active,
|
||||
is_pinned,
|
||||
requires_ack,
|
||||
author_id,
|
||||
(SELECT username FROM users WHERE id = announcements.author_id) AS author_username,
|
||||
EXTRACT(EPOCH FROM start_time)::bigint AS start_time_unix_secs,
|
||||
@@ -139,8 +176,9 @@ SET
|
||||
priority = COALESCE($5, priority),
|
||||
is_active = COALESCE($6, is_active),
|
||||
is_pinned = COALESCE($7, is_pinned),
|
||||
start_time = COALESCE($8, start_time),
|
||||
end_time = COALESCE($9, end_time),
|
||||
requires_ack = COALESCE($8, requires_ack),
|
||||
start_time = COALESCE($9, start_time),
|
||||
end_time = COALESCE($10, end_time),
|
||||
updated_at = NOW()
|
||||
WHERE id = $1
|
||||
RETURNING
|
||||
@@ -151,6 +189,7 @@ RETURNING
|
||||
priority,
|
||||
is_active,
|
||||
is_pinned,
|
||||
requires_ack,
|
||||
author_id,
|
||||
(SELECT username FROM users WHERE id = announcements.author_id) AS author_username,
|
||||
EXTRACT(EPOCH FROM start_time)::bigint AS start_time_unix_secs,
|
||||
@@ -252,6 +291,24 @@ impl AnnouncementReadRepository for SqlxAnnouncementReadRepository {
|
||||
.map_postgres_err()?;
|
||||
Ok(row.try_get::<i64, _>("total").map_postgres_err()?.max(0) as u64)
|
||||
}
|
||||
|
||||
async fn list_required_unread_active_announcements(
|
||||
&self,
|
||||
user_id: &str,
|
||||
now_unix_secs: u64,
|
||||
limit: usize,
|
||||
) -> Result<Vec<StoredAnnouncement>, DataLayerError> {
|
||||
let mut rows = sqlx::query(LIST_REQUIRED_UNREAD_ACTIVE_ANNOUNCEMENTS_SQL)
|
||||
.bind(user_id)
|
||||
.bind(now_unix_secs as f64)
|
||||
.bind(limit as i64)
|
||||
.fetch(&self.pool);
|
||||
let mut items = Vec::new();
|
||||
while let Some(row) = rows.try_next().await.map_postgres_err()? {
|
||||
items.push(map_announcement_row(&row)?);
|
||||
}
|
||||
Ok(items)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -269,6 +326,7 @@ impl AnnouncementWriteRepository for SqlxAnnouncementReadRepository {
|
||||
.bind(record.priority)
|
||||
.bind(record.author_id)
|
||||
.bind(record.is_pinned)
|
||||
.bind(record.requires_ack)
|
||||
.bind(optional_datetime(record.start_time_unix_secs))
|
||||
.bind(optional_datetime(record.end_time_unix_secs))
|
||||
.fetch_one(&self.pool)
|
||||
@@ -290,6 +348,7 @@ impl AnnouncementWriteRepository for SqlxAnnouncementReadRepository {
|
||||
.bind(record.priority)
|
||||
.bind(record.is_active)
|
||||
.bind(record.is_pinned)
|
||||
.bind(record.requires_ack)
|
||||
.bind(optional_datetime(record.start_time_unix_secs))
|
||||
.bind(optional_datetime(record.end_time_unix_secs))
|
||||
.fetch_optional(&self.pool)
|
||||
@@ -356,6 +415,7 @@ fn map_announcement_row(row: &PgRow) -> Result<StoredAnnouncement, DataLayerErro
|
||||
row.try_get("priority").map_postgres_err()?,
|
||||
row.try_get("is_active").map_postgres_err()?,
|
||||
row.try_get("is_pinned").map_postgres_err()?,
|
||||
row.try_get("requires_ack").map_postgres_err()?,
|
||||
row.try_get("author_id").map_postgres_err()?,
|
||||
row.try_get("author_username").map_postgres_err()?,
|
||||
row.try_get("start_time_unix_secs").map_postgres_err()?,
|
||||
|
||||
@@ -18,6 +18,7 @@ SELECT
|
||||
a.priority,
|
||||
a.is_active,
|
||||
a.is_pinned,
|
||||
a.requires_ack,
|
||||
a.author_id,
|
||||
u.username AS author_username,
|
||||
a.start_time AS start_time_unix_secs,
|
||||
@@ -144,6 +145,39 @@ WHERE a.is_active = 1
|
||||
.map_sql_err()?;
|
||||
Ok(row.try_get::<i64, _>("total").map_sql_err()?.max(0) as u64)
|
||||
}
|
||||
|
||||
async fn list_required_unread_active_announcements(
|
||||
&self,
|
||||
user_id: &str,
|
||||
now_unix_secs: u64,
|
||||
limit: usize,
|
||||
) -> Result<Vec<StoredAnnouncement>, DataLayerError> {
|
||||
let rows = sqlx::query(&format!(
|
||||
r#"
|
||||
{ANNOUNCEMENT_SELECT}
|
||||
WHERE a.is_active = 1
|
||||
AND a.requires_ack = 1
|
||||
AND (a.start_time IS NULL OR a.start_time <= ?)
|
||||
AND (a.end_time IS NULL OR a.end_time >= ?)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM announcement_reads r
|
||||
WHERE r.user_id = ?
|
||||
AND r.announcement_id = a.id
|
||||
)
|
||||
ORDER BY a.is_pinned DESC, a.priority DESC, a.created_at DESC, a.id ASC
|
||||
LIMIT ?
|
||||
"#
|
||||
))
|
||||
.bind(now_unix_secs as i64)
|
||||
.bind(now_unix_secs as i64)
|
||||
.bind(user_id)
|
||||
.bind(limit as i64)
|
||||
.fetch_all(&self.pool)
|
||||
.await
|
||||
.map_sql_err()?;
|
||||
rows.iter().map(map_announcement_row).collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -159,9 +193,9 @@ impl AnnouncementWriteRepository for SqliteAnnouncementRepository {
|
||||
r#"
|
||||
INSERT INTO announcements (
|
||||
id, title, content, type, priority, author_id, is_active, is_pinned,
|
||||
start_time, end_time, created_at, updated_at
|
||||
requires_ack, start_time, end_time, created_at, updated_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?)
|
||||
VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?)
|
||||
"#,
|
||||
)
|
||||
.bind(&id)
|
||||
@@ -171,6 +205,7 @@ VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?)
|
||||
.bind(record.priority)
|
||||
.bind(record.author_id)
|
||||
.bind(record.is_pinned)
|
||||
.bind(record.requires_ack)
|
||||
.bind(optional_i64_from_u64(
|
||||
record.start_time_unix_secs,
|
||||
"announcements.start_time",
|
||||
@@ -204,6 +239,7 @@ SET title = COALESCE(?, title),
|
||||
priority = COALESCE(?, priority),
|
||||
is_active = COALESCE(?, is_active),
|
||||
is_pinned = COALESCE(?, is_pinned),
|
||||
requires_ack = COALESCE(?, requires_ack),
|
||||
start_time = COALESCE(?, start_time),
|
||||
end_time = COALESCE(?, end_time),
|
||||
updated_at = ?
|
||||
@@ -216,6 +252,7 @@ WHERE id = ?
|
||||
.bind(record.priority)
|
||||
.bind(record.is_active)
|
||||
.bind(record.is_pinned)
|
||||
.bind(record.requires_ack)
|
||||
.bind(optional_i64_from_u64(
|
||||
record.start_time_unix_secs,
|
||||
"announcements.start_time",
|
||||
@@ -303,6 +340,7 @@ fn map_announcement_row(row: &SqliteRow) -> Result<StoredAnnouncement, DataLayer
|
||||
row.try_get("priority").map_sql_err()?,
|
||||
row.try_get("is_active").map_sql_err()?,
|
||||
row.try_get("is_pinned").map_sql_err()?,
|
||||
row.try_get("requires_ack").map_sql_err()?,
|
||||
row.try_get("author_id").map_sql_err()?,
|
||||
row.try_get("author_username").map_sql_err()?,
|
||||
row.try_get("start_time_unix_secs").map_sql_err()?,
|
||||
@@ -341,6 +379,7 @@ mod tests {
|
||||
kind: "info".to_string(),
|
||||
priority: 10,
|
||||
is_pinned: true,
|
||||
requires_ack: false,
|
||||
author_id: "user-1".to_string(),
|
||||
start_time_unix_secs: Some(100),
|
||||
end_time_unix_secs: Some(300),
|
||||
@@ -392,6 +431,7 @@ mod tests {
|
||||
priority: Some(20),
|
||||
is_active: Some(false),
|
||||
is_pinned: Some(false),
|
||||
requires_ack: Some(true),
|
||||
start_time_unix_secs: None,
|
||||
end_time_unix_secs: None,
|
||||
})
|
||||
|
||||
@@ -9,6 +9,7 @@ pub struct StoredAnnouncement {
|
||||
pub priority: i32,
|
||||
pub is_active: bool,
|
||||
pub is_pinned: bool,
|
||||
pub requires_ack: bool,
|
||||
pub author_id: Option<String>,
|
||||
pub author_username: Option<String>,
|
||||
pub start_time_unix_secs: Option<u64>,
|
||||
@@ -27,6 +28,7 @@ impl StoredAnnouncement {
|
||||
priority: i32,
|
||||
is_active: bool,
|
||||
is_pinned: bool,
|
||||
requires_ack: bool,
|
||||
author_id: Option<String>,
|
||||
author_username: Option<String>,
|
||||
start_time_unix_secs: Option<i64>,
|
||||
@@ -63,6 +65,7 @@ impl StoredAnnouncement {
|
||||
priority,
|
||||
is_active,
|
||||
is_pinned,
|
||||
requires_ack,
|
||||
author_id,
|
||||
author_username,
|
||||
start_time_unix_secs: start_time_unix_secs
|
||||
@@ -117,6 +120,13 @@ pub trait AnnouncementReadRepository: Send + Sync {
|
||||
user_id: &str,
|
||||
now_unix_secs: u64,
|
||||
) -> Result<u64, crate::DataLayerError>;
|
||||
|
||||
async fn list_required_unread_active_announcements(
|
||||
&self,
|
||||
user_id: &str,
|
||||
now_unix_secs: u64,
|
||||
limit: usize,
|
||||
) -> Result<Vec<StoredAnnouncement>, crate::DataLayerError>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
@@ -126,6 +136,7 @@ pub struct CreateAnnouncementRecord {
|
||||
pub kind: String,
|
||||
pub priority: i32,
|
||||
pub is_pinned: bool,
|
||||
pub requires_ack: bool,
|
||||
pub author_id: String,
|
||||
pub start_time_unix_secs: Option<u64>,
|
||||
pub end_time_unix_secs: Option<u64>,
|
||||
@@ -166,6 +177,7 @@ pub struct UpdateAnnouncementRecord {
|
||||
pub priority: Option<i32>,
|
||||
pub is_active: Option<bool>,
|
||||
pub is_pinned: Option<bool>,
|
||||
pub requires_ack: Option<bool>,
|
||||
pub start_time_unix_secs: Option<u64>,
|
||||
pub end_time_unix_secs: Option<u64>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user