Skip to content

Commit f0cb4c5

Browse files
committed
create visitor log
1 parent 61f2908 commit f0cb4c5

File tree

8 files changed

+206
-27
lines changed

8 files changed

+206
-27
lines changed

src/api/cms_api.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,12 @@ impl Cms for CmsApi {
3636
// let headers = request.g
3737
let remote_addr: Option<SocketAddr> = request.remote_addr();
3838

39-
// Log or use the remote address as needed
40-
if let Some(addr) = remote_addr {
41-
println!("Request from: {}", addr);
42-
} else {
43-
println!("Could not determine remote address.");
44-
}
45-
4639
let req = request.into_inner();
4740

4841
match self
4942
.state
5043
.cms_service
51-
.get_cms_content(req, &self.state.db)
44+
.get_cms_content(req, remote_addr, &self.state.db)
5245
.await
5346
{
5447
Ok(reply) => Ok(Response::new(reply)),

src/api/proto/setting.rs

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,69 @@
11
// This file is @generated by prost-build.
22
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
3+
/// setting model
34
pub struct SettingModel {
45
#[prost(string, tag = "1")]
6+
/// id
57
pub id: ::prost::alloc::string::String,
68
#[prost(string, tag = "2")]
9+
/// identifier
710
pub identifier: ::prost::alloc::string::String,
811
#[prost(string, tag = "3")]
12+
/// value
913
pub value: ::prost::alloc::string::String,
1014
#[prost(message, optional, tag = "4")]
15+
/// created at
1116
pub created_at: ::core::option::Option<::prost_types::Timestamp>,
1217
#[prost(message, optional, tag = "5")]
18+
/// updated at
1319
pub updated_at: ::core::option::Option<::prost_types::Timestamp>,
20+
1421
#[prost(string, tag = "6")]
22+
/// created by
1523
pub created_by: ::prost::alloc::string::String,
1624
#[prost(string, tag = "7")]
25+
/// updated by
1726
pub updated_by: ::prost::alloc::string::String,
1827
}
1928
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
29+
/// setting save model
2030
pub struct SettingSaveModel {
2131
#[prost(string, tag = "1")]
32+
/// id
2233
pub id: ::prost::alloc::string::String,
2334
#[prost(string, tag = "2")]
35+
/// identifier
2436
pub identifier: ::prost::alloc::string::String,
2537
#[prost(string, tag = "3")]
38+
/// value
2639
pub value: ::prost::alloc::string::String,
2740
}
2841
/// Setting services
2942
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
43+
/// get setting request
3044
pub struct GetSettingRequest {}
3145
#[derive(Clone, PartialEq, ::prost::Message)]
46+
/// get setting response
3247
pub struct GetSettingResponse {
3348
#[prost(bool, tag = "1")]
49+
/// status
3450
pub status: bool,
3551
#[prost(message, repeated, tag = "2")]
52+
/// data
3653
pub data: ::prost::alloc::vec::Vec<SettingModel>,
3754
}
3855
#[derive(Clone, PartialEq, ::prost::Message)]
56+
/// store setting request
3957
pub struct StoreSettingRequest {
4058
#[prost(message, repeated, tag = "1")]
59+
/// data
4160
pub data: ::prost::alloc::vec::Vec<SettingSaveModel>,
4261
}
4362
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
63+
/// store setting request
4464
pub struct StoreSettingResponse {
4565
#[prost(bool, tag = "1")]
66+
/// status
4667
pub status: bool,
4768
}
4869
/// Generated client implementations.
@@ -75,8 +96,8 @@ pub mod setting_client {
7596
where
7697
T: tonic::client::GrpcService<tonic::body::Body>,
7798
T::Error: Into<StdError>,
78-
T::ResponseBody: Body<Data = Bytes> + std::marker::Send + 'static,
79-
<T::ResponseBody as Body>::Error: Into<StdError> + std::marker::Send,
99+
T::ResponseBody: Body<Data = Bytes> + Send + 'static,
100+
<T::ResponseBody as Body>::Error: Into<StdError> + Send,
80101
{
81102
pub fn new(inner: T) -> Self {
82103
let inner = tonic::client::Grpc::new(inner);
@@ -93,15 +114,15 @@ pub mod setting_client {
93114
where
94115
F: tonic::service::Interceptor,
95116
T::ResponseBody: Default,
96-
T: tonic::codegen::Service<
117+
T: Service<
97118
http::Request<tonic::body::Body>,
98119
Response = http::Response<
99120
<T as tonic::client::GrpcService<tonic::body::Body>>::ResponseBody,
100121
>,
101122
>,
102-
<T as tonic::codegen::Service<
123+
<T as Service<
103124
http::Request<tonic::body::Body>,
104-
>>::Error: Into<StdError> + std::marker::Send + std::marker::Sync,
125+
>>::Error: Into<StdError> + Send + Sync,
105126
{
106127
SettingClient::new(InterceptedService::new(inner, interceptor))
107128
}
@@ -139,7 +160,7 @@ pub mod setting_client {
139160
pub async fn get_setting(
140161
&mut self,
141162
request: impl tonic::IntoRequest<super::GetSettingRequest>,
142-
) -> std::result::Result<
163+
) -> Result<
143164
tonic::Response<super::GetSettingResponse>,
144165
tonic::Status,
145166
> {
@@ -163,7 +184,7 @@ pub mod setting_client {
163184
pub async fn store_setting(
164185
&mut self,
165186
request: impl tonic::IntoRequest<super::StoreSettingRequest>,
166-
) -> std::result::Result<
187+
) -> Result<
167188
tonic::Response<super::StoreSettingResponse>,
168189
tonic::Status,
169190
> {
@@ -198,18 +219,18 @@ pub mod setting_server {
198219
use tonic::codegen::*;
199220
/// Generated trait containing gRPC methods that should be implemented for use with SettingServer.
200221
#[async_trait]
201-
pub trait Setting: std::marker::Send + std::marker::Sync + 'static {
222+
pub trait Setting: Send + Sync + 'static {
202223
async fn get_setting(
203224
&self,
204225
request: tonic::Request<super::GetSettingRequest>,
205-
) -> std::result::Result<
226+
) -> Result<
206227
tonic::Response<super::GetSettingResponse>,
207228
tonic::Status,
208229
>;
209230
async fn store_setting(
210231
&self,
211232
request: tonic::Request<super::StoreSettingRequest>,
212-
) -> std::result::Result<
233+
) -> Result<
213234
tonic::Response<super::StoreSettingResponse>,
214235
tonic::Status,
215236
>;
@@ -273,19 +294,19 @@ pub mod setting_server {
273294
self
274295
}
275296
}
276-
impl<T, B> tonic::codegen::Service<http::Request<B>> for SettingServer<T>
297+
impl<T, B> Service<http::Request<B>> for SettingServer<T>
277298
where
278299
T: Setting,
279-
B: Body + std::marker::Send + 'static,
280-
B::Error: Into<StdError> + std::marker::Send + 'static,
300+
B: Body + Send + 'static,
301+
B::Error: Into<StdError> + Send + 'static,
281302
{
282303
type Response = http::Response<tonic::body::Body>;
283304
type Error = std::convert::Infallible;
284305
type Future = BoxFuture<Self::Response, Self::Error>;
285306
fn poll_ready(
286307
&mut self,
287308
_cx: &mut Context<'_>,
288-
) -> Poll<std::result::Result<(), Self::Error>> {
309+
) -> Poll<Result<(), Self::Error>> {
289310
Poll::Ready(Ok(()))
290311
}
291312
fn call(&mut self, req: http::Request<B>) -> Self::Future {

src/avored_state.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::repositories::role_repository::RoleRepository;
1111
use crate::repositories::security_alert_repository::SecurityAlertRepository;
1212
// use crate::repositories::security_audit_repository::SecurityAuditRepository;
1313
use crate::repositories::setting_repository::SettingRepository;
14+
use crate::repositories::visitor_log_repository::VisitorLogRepository;
1415
use crate::services::admin_user_service::AdminUserService;
1516
use crate::services::asset_service::AssetService;
1617
use crate::services::auth_service::AuthService;
@@ -83,6 +84,7 @@ impl AvoRedState {
8384
let setting_repository = SettingRepository::new();
8485
// let security_audit_repository = SecurityAuditRepository::new();
8586
let security_alert_repository = SecurityAlertRepository::new();
87+
let visitor_log_repository = VisitorLogRepository::new();
8688

8789
let misc_service = MiscService::new().await?;
8890
let auth_service =
@@ -92,7 +94,7 @@ impl AvoRedState {
9294
ContentService::new(content_repository.clone(), collection_repository)?;
9395
let asset_service = AssetService::new(asset_repository)?;
9496
let setting_service = SettingService::new(setting_repository)?;
95-
let cms_service = CmsService::new(content_repository)?;
97+
let cms_service = CmsService::new(content_repository, visitor_log_repository)?;
9698
let general_service = GeneralService::new()?;
9799
// let security_audit_service = SecurityAuditService::new(security_audit_repository);
98100
// let security_alert_service = SecurityAlertService::new(security_alert_repository);

src/models/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ pub mod token_claim_model;
4040
/// validation module
4141
pub mod validation_error;
4242

43+
/// visitor log module
44+
pub mod visitor_log_model;
4345

4446
// /// Pagination struct
4547
// #[derive(Serialize, Debug, Deserialize, Clone, Default)]

src/models/visitor_log_model.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
use serde::{Deserialize, Serialize};
2+
use surrealdb::sql::{Datetime, Object};
3+
use crate::error::{Error, Result};
4+
use super::BaseModel;
5+
6+
7+
// region: Struct initialze
8+
9+
/// Represents an visitor log model in the system.
10+
#[derive(Serialize, Debug, Deserialize, Clone, Default)]
11+
pub struct VistitorLogModel {
12+
13+
/// The unique identifier for the visitor log.
14+
pub id: String,
15+
16+
/// The content tpye of the visitor log.
17+
pub content_type: String,
18+
19+
/// The content id of the visitor log.
20+
pub content_id: String,
21+
22+
/// The IP address of the visitor log
23+
pub ip_address: Option<String>,
24+
25+
/// The date and time when the visitor log was created.
26+
pub created_at: Datetime
27+
}
28+
29+
/// Represents a model for creating an visitor log.
30+
#[derive(Serialize, Debug, Deserialize, Clone)]
31+
pub struct CreatableVisitorLogModel {
32+
/// The content type of the visitor log.
33+
pub content_type: String,
34+
35+
/// The content identifier of the visitor log.
36+
pub content_id: String,
37+
38+
/// The password of the visitor log.
39+
pub ip_address: Option<String>,
40+
}
41+
42+
// endregion: Struct initialize
43+
44+
45+
46+
47+
48+
// region: impl
49+
50+
impl TryFrom<Object> for VistitorLogModel {
51+
type Error = Error;
52+
fn try_from(val: Object) -> Result<Self> {
53+
let id: String = val.get("id").get_id()?;
54+
let content_id = val.get("content_id").get_string()?;
55+
let content_type = val.get("content_type").get_string()?;
56+
let ip_address = val.get("ip_address").get_string()?;
57+
let created_at = val.get("created_at").get_datetime()?;
58+
59+
Ok(Self {
60+
id,
61+
content_id,
62+
content_type,
63+
ip_address: Some(ip_address),
64+
created_at,
65+
})
66+
}
67+
}
68+
69+
70+
// endregion: impl

src/repositories/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ pub mod security_audit_repository;
3333
/// setting repository
3434
pub mod setting_repository;
3535

36+
/// visitor log repository module
37+
pub mod visitor_log_repository;
38+
3639

3740
/// into iter object
3841
pub fn into_iter_objects(responses: Vec<Response>) -> Result<impl Iterator<Item = Result<Object>>> {
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
use crate::error::{Error, Result};
2+
use crate::models::visitor_log_model::{CreatableVisitorLogModel, VistitorLogModel};
3+
use crate::repositories::into_iter_objects;
4+
use surrealdb::dbs::Session;
5+
use surrealdb::kvs::Datastore;
6+
use surrealdb::sql::Datetime;
7+
use std::collections::BTreeMap;
8+
use surrealdb::sql::Value;
9+
10+
/// visitor log repository
11+
#[derive(Clone)]
12+
pub struct VisitorLogRepository {}
13+
14+
impl Default for VisitorLogRepository {
15+
fn default() -> Self {
16+
Self::new()
17+
}
18+
}
19+
20+
impl VisitorLogRepository {
21+
/// new instance password repository
22+
#[must_use] pub const fn new() -> Self {
23+
Self {}
24+
}
25+
26+
/// create visitor log record in table
27+
pub async fn create(
28+
&self,
29+
datastore: &Datastore,
30+
database_session: &Session,
31+
creatable_visitor_log: CreatableVisitorLogModel
32+
) -> Result<VistitorLogModel> {
33+
34+
let sql = "CREATE visitor_log CONTENT $data";
35+
36+
let data: BTreeMap<String, Value> = [
37+
(
38+
"content_type".into(),
39+
creatable_visitor_log.content_type.into(),
40+
),
41+
(
42+
"content_id".into(),
43+
creatable_visitor_log.content_id.into(),
44+
),
45+
(
46+
"ip_address".into(),
47+
creatable_visitor_log.ip_address.into(),
48+
),
49+
("created_at".into(), Datetime::default().into()),
50+
]
51+
.into();
52+
let vars: BTreeMap<String, Value> = [("data".into(), data.into())].into();
53+
54+
let ress = datastore.execute(sql, database_session, Some(vars)).await?;
55+
56+
let result_object_option = into_iter_objects(ress)?.next();
57+
let result_object = match result_object_option {
58+
Some(object) => object,
59+
None => Err(Error::Generic("no record found".to_string())),
60+
};
61+
let visitor_log_model: Result<VistitorLogModel> = result_object?.try_into();
62+
63+
visitor_log_model
64+
65+
}
66+
}

0 commit comments

Comments
 (0)