@@ -7,9 +7,10 @@ use crate::models::{
77} ;
88use axum:: {
99 debug_handler,
10- extract:: { Query , Request } ,
11- http:: { header , HeaderMap , StatusCode } ,
10+ extract:: Query ,
11+ http:: { HeaderMap , StatusCode } ,
1212} ;
13+ use axum_client_ip:: { InsecureClientIp , SecureClientIp } ;
1314use chrono:: { Duration , Utc } ;
1415use loco_rs:: prelude:: * ;
1516use serde:: Deserialize ;
@@ -122,23 +123,63 @@ pub async fn create(
122123pub async fn increase_views (
123124 State ( _ctx) : State < AppContext > ,
124125 Path ( id) : Path < i32 > ,
125- req : Request ,
126+ insecure_ip : InsecureClientIp ,
127+ headers : HeaderMap ,
126128) -> Result < Response > {
127- let post_model = posts:: Model :: by_id ( id)
128- . await
129+ let ip_str = insecure_ip. 0 . to_string ( ) ;
130+ let now = Utc :: now ( ) ;
131+ let cutoff = now - Duration :: hours ( 6 ) ;
132+
133+ let mut post = posts:: Entity :: find_by_id ( id)
129134 . one ( & _ctx. db )
130135 . await ?
131- . ok_or_else ( || Error :: NotFound ) ?;
132- let cutoff = Utc :: now ( ) - Duration :: hours ( 6 ) ;
133- println ! ( "{:?}" , req. headers( ) ) ;
134- // let ip = headers
135- // .get()
136- // .and_then(|value| value.to_str().ok())
137- // .and_then(|x_forwarded| x_forwarded.split(',').next())
138- // .unwrap_or_else(|| String::from("default-ip"));
139- // let already_viewed = post_model
140- // .find_related(post_views::Entity)
141- // .filter(post_views::Column::IpAddress.eq(ip));
136+ . ok_or ( Error :: NotFound ) ?;
137+
138+ let recent_view = post_views:: Entity :: find ( )
139+ . filter ( post_views:: Column :: PostId . eq ( post. id ) )
140+ . filter ( post_views:: Column :: IpAddress . eq ( ip_str. clone ( ) ) )
141+ . filter ( post_views:: Column :: CreatedAt . gt ( cutoff) )
142+ . one ( & _ctx. db )
143+ . await ?;
144+
145+ if recent_view. is_none ( ) {
146+ let user_agent = headers
147+ . get ( "user-agent" )
148+ . and_then ( |v| v. to_str ( ) . ok ( ) )
149+ . map ( |s| s. to_string ( ) ) ;
150+
151+ let referer = headers
152+ . get ( "referer" )
153+ . and_then ( |v| v. to_str ( ) . ok ( ) )
154+ . map ( |s| s. to_string ( ) ) ;
155+
156+ let device_type = user_agent
157+ . as_ref ( )
158+ . map ( |ua| {
159+ if ua. contains ( "Mobile" ) {
160+ Some ( "mobile" )
161+ } else if ua. contains ( "Tablet" ) {
162+ Some ( "tablet" )
163+ } else {
164+ Some ( "desktop" )
165+ }
166+ } )
167+ . flatten ( )
168+ . map ( String :: from) ;
169+
170+ let view = post_views:: ActiveModel {
171+ post_id : Set ( post. id ) ,
172+ ip_address : Set ( ip_str) ,
173+ user_agent : Set ( user_agent) ,
174+ referer : Set ( referer) ,
175+ device_type : Set ( device_type) ,
176+ ..Default :: default ( )
177+ } ;
178+ view. insert ( & _ctx. db ) . await ?;
179+ let mut active_post = post. clone ( ) . into_active_model ( ) . clone ( ) ;
180+ active_post. views = Set ( post. views + 1 ) ;
181+ active_post. update ( & _ctx. db ) . await ?;
182+ }
142183
143184 format:: text ( "Views Increased" )
144185}
0 commit comments