1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
//! Services for the admin panel.

mod semesters;

use crate::api::rcos::users::role_lookup::RoleLookup;
use crate::api::rcos::users::UserRole;
use crate::error::TelescopeError;
use crate::templates::page::Page;
use crate::templates::Template;
use crate::web::middlewares::authorization::{Authorization, AuthorizationResult};
use actix_web::guard;
use actix_web::web as aweb;
use actix_web::web::ServiceConfig;
use actix_web::HttpRequest;
use futures::future::LocalBoxFuture;
use uuid::Uuid;

/// Check that a user is an admin.
fn admin_authorization(user_id: Uuid) -> LocalBoxFuture<'static, AuthorizationResult> {
    Box::pin(async move {
        // Then check that their role is admin.
        let role: UserRole = RoleLookup::get(user_id)
            .await?
            // The role should not be none, since the account needs to exist at this point.
            .expect("Viewer's account does not exist.");

        // Forbid access unless the user is an admin.
        if !role.is_admin() {
            Err(TelescopeError::Forbidden)
        } else {
            Ok(())
        }
    })
}

/// Register admin panel services.
pub fn register(config: &mut ServiceConfig) {
    // Create admin authorization middleware.
    let admin_authorization_middleware: Authorization = Authorization::new(admin_authorization);

    // Admin panel index page.
    config.service(
        aweb::resource("/admin")
            .guard(guard::Get())
            .wrap(admin_authorization_middleware.clone())
            .to(index),
    );

    // Route every sub-service through the admin scope.
    config.service(
        // Create the admin scope.
        aweb::scope("/admin/")
            // Verify that the viewer has the admin role.
            .wrap(admin_authorization_middleware)
            // Semester services
            .configure(semesters::register),
    );
}

/// Admin page index.
async fn index(req: HttpRequest) -> Result<Page, TelescopeError> {
    // Access is pre-checked by the scope this is in.
    // Return the admin page (currently just a static template).
    return Template::new("admin/index")
        // Rendered in a page of course.
        .in_page(&req, "RCOS Admin")
        .await;
}