parent
32a2151ba0
commit
d3465b4e10
3
migrations/2021-02-09-175834_add_statistics/down.sql
Normal file
3
migrations/2021-02-09-175834_add_statistics/down.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
-- This file should undo anything in `up.sql`
|
||||||
|
|
||||||
|
DROP TABLE clicks;
|
13
migrations/2021-02-09-175834_add_statistics/up.sql
Normal file
13
migrations/2021-02-09-175834_add_statistics/up.sql
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
-- Your SQL goes here
|
||||||
|
|
||||||
|
CREATE TABLE clicks
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
link INT NOT NULL,
|
||||||
|
created_at TIMESTAMP NOT NULL,
|
||||||
|
|
||||||
|
FOREIGN KEY
|
||||||
|
(link)
|
||||||
|
REFERENCES links
|
||||||
|
(id)
|
||||||
|
);
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{forms::LinkForm, ServerError};
|
use crate::{forms::LinkForm, ServerError};
|
||||||
|
|
||||||
use super::schema::{links, users};
|
use super::schema::{clicks, links, users};
|
||||||
use argonautica::Hasher;
|
use argonautica::Hasher;
|
||||||
use diesel::{Insertable, Queryable};
|
use diesel::{Insertable, Queryable};
|
||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
@ -89,3 +89,31 @@ impl NewLink {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Debug, Queryable)]
|
||||||
|
pub struct Click {
|
||||||
|
pub id: i32,
|
||||||
|
pub link: i32,
|
||||||
|
pub created_at: chrono::NaiveDateTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Insertable)]
|
||||||
|
#[table_name = "clicks"]
|
||||||
|
pub struct NewClick {
|
||||||
|
pub link: i32,
|
||||||
|
pub created_at: chrono::NaiveDateTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NewClick {
|
||||||
|
pub fn new(link_id: i32) -> Self {
|
||||||
|
Self {
|
||||||
|
link: link_id,
|
||||||
|
created_at: chrono::Local::now().naive_utc(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Debug, Queryable)]
|
||||||
|
pub struct Count {
|
||||||
|
count: i32,
|
||||||
|
}
|
||||||
|
@ -1,3 +1,11 @@
|
|||||||
|
table! {
|
||||||
|
clicks (id) {
|
||||||
|
id -> Integer,
|
||||||
|
link -> Integer,
|
||||||
|
created_at -> Timestamp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
table! {
|
table! {
|
||||||
links (id) {
|
links (id) {
|
||||||
id -> Integer,
|
id -> Integer,
|
||||||
@ -18,6 +26,7 @@ table! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
joinable!(clicks -> links (link));
|
||||||
joinable!(links -> users (author));
|
joinable!(links -> users (author));
|
||||||
|
|
||||||
allow_tables_to_appear_in_same_query!(links, users,);
|
allow_tables_to_appear_in_same_query!(clicks, links, users,);
|
||||||
|
40
src/views.rs
40
src/views.rs
@ -1,6 +1,5 @@
|
|||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
use crate::ServerError;
|
|
||||||
use actix_identity::Identity;
|
use actix_identity::Identity;
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
http::header::{CacheControl, CacheDirective, ContentType, Expires},
|
http::header::{CacheControl, CacheDirective, ContentType, Expires},
|
||||||
@ -14,7 +13,8 @@ use qrcode::{render::svg, QrCode};
|
|||||||
use tera::{Context, Tera};
|
use tera::{Context, Tera};
|
||||||
|
|
||||||
use super::forms::LinkForm;
|
use super::forms::LinkForm;
|
||||||
use super::models::{Link, LoginUser, NewLink, NewUser, User};
|
use super::models::{Count, Link, LoginUser, NewClick, NewLink, NewUser, User};
|
||||||
|
use crate::ServerError;
|
||||||
|
|
||||||
fn establish_connection() -> Result<SqliteConnection, ServerError> {
|
fn establish_connection() -> Result<SqliteConnection, ServerError> {
|
||||||
dotenv().ok();
|
dotenv().ok();
|
||||||
@ -49,11 +49,30 @@ pub(crate) async fn index(
|
|||||||
tera: web::Data<Tera>,
|
tera: web::Data<Tera>,
|
||||||
id: Identity,
|
id: Identity,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
use super::schema::links::dsl::links;
|
use super::schema::clicks;
|
||||||
use super::schema::users::dsl::users;
|
use super::schema::links;
|
||||||
|
use super::schema::users;
|
||||||
if let Some(id) = id.identity() {
|
if let Some(id) = id.identity() {
|
||||||
let connection = establish_connection()?;
|
let connection = establish_connection()?;
|
||||||
let all_links: Vec<(Link, User)> = links.inner_join(users).load(&connection)?;
|
let query = links::dsl::links
|
||||||
|
.inner_join(users::dsl::users)
|
||||||
|
.left_join(clicks::dsl::clicks)
|
||||||
|
.group_by(links::id)
|
||||||
|
.select((
|
||||||
|
(
|
||||||
|
links::id,
|
||||||
|
links::title,
|
||||||
|
links::target,
|
||||||
|
links::code,
|
||||||
|
links::author,
|
||||||
|
links::created_at,
|
||||||
|
),
|
||||||
|
(users::id, users::username, users::email, users::password),
|
||||||
|
(diesel::dsl::sql::<diesel::sql_types::Integer>(
|
||||||
|
"COUNT(clicks.id)",
|
||||||
|
),),
|
||||||
|
));
|
||||||
|
let all_links: Vec<(Link, User, Count)> = query.load(&connection)?;
|
||||||
|
|
||||||
let mut data = Context::new();
|
let mut data = Context::new();
|
||||||
data.insert("name", &id);
|
data.insert("name", &id);
|
||||||
@ -367,7 +386,16 @@ pub(crate) async fn redirect(
|
|||||||
|
|
||||||
let link = links.filter(code.eq(&data.0)).first::<Link>(&connection);
|
let link = links.filter(code.eq(&data.0)).first::<Link>(&connection);
|
||||||
match link {
|
match link {
|
||||||
Ok(link) => Ok(redirect_builder(&link.target)),
|
Ok(link) => {
|
||||||
|
use super::schema::clicks;
|
||||||
|
let new_click = NewClick::new(link.id);
|
||||||
|
let connection = establish_connection()?;
|
||||||
|
|
||||||
|
diesel::insert_into(clicks::table)
|
||||||
|
.values(&new_click)
|
||||||
|
.execute(&connection)?;
|
||||||
|
Ok(redirect_builder(&link.target))
|
||||||
|
}
|
||||||
Err(NotFound) => {
|
Err(NotFound) => {
|
||||||
let mut data = Context::new();
|
let mut data = Context::new();
|
||||||
data.insert("title", "Wurde gelöscht");
|
data.insert("title", "Wurde gelöscht");
|
||||||
|
@ -19,10 +19,14 @@
|
|||||||
<th>
|
<th>
|
||||||
Benutzername
|
Benutzername
|
||||||
</th>
|
</th>
|
||||||
|
<th>
|
||||||
|
Statistik
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
{% for links_user in links_per_users %}
|
{% for links_user in links_per_users %}
|
||||||
{% set l = links_user[0] %}
|
{% set l = links_user[0] %}
|
||||||
{% set u = links_user[1] %}
|
{% set u = links_user[1] %}
|
||||||
|
{% set c = links_user[2] %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<a href="/admin/view/link/{{l.code}}"><span>{{l.code}}</span>
|
<a href="/admin/view/link/{{l.code}}"><span>{{l.code}}</span>
|
||||||
@ -37,6 +41,9 @@
|
|||||||
<a href="/admin/view/profile/{{u.id}}"><small>{{ u.username }}</small>
|
<a href="/admin/view/profile/{{u.id}}"><small>{{ u.username }}</small>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ c.count }}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
|
Loading…
Reference in New Issue
Block a user