...
This commit is contained in:
parent
15b05cb599
commit
34594b95fa
@ -2,6 +2,7 @@ use actix_web::{web, HttpResponse, Responder, Result, http::header, cookie::Cook
|
||||
use actix_session::Session;
|
||||
use tera::Tera;
|
||||
use crate::models::user::{User, LoginCredentials, RegistrationData, UserRole};
|
||||
use crate::utils::render_template;
|
||||
use jsonwebtoken::{encode, decode, Header, Algorithm, Validation, EncodingKey, DecodingKey};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use chrono::{Utc, Duration};
|
||||
@ -91,13 +92,7 @@ impl AuthController {
|
||||
let mut ctx = tera::Context::new();
|
||||
ctx.insert("active_page", "login");
|
||||
|
||||
let rendered = tmpl.render("auth/login.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "auth/login.html", &ctx)
|
||||
}
|
||||
|
||||
/// Handles user login
|
||||
@ -146,13 +141,7 @@ impl AuthController {
|
||||
let mut ctx = tera::Context::new();
|
||||
ctx.insert("active_page", "register");
|
||||
|
||||
let rendered = tmpl.render("auth/register.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "auth/register.html", &ctx)
|
||||
}
|
||||
|
||||
/// Handles user registration
|
||||
|
@ -6,7 +6,7 @@ use tera::Tera;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::models::{CalendarEvent, CalendarViewMode};
|
||||
use crate::utils::RedisCalendarService;
|
||||
use crate::utils::{RedisCalendarService, render_template};
|
||||
|
||||
/// Controller for handling calendar-related routes
|
||||
pub struct CalendarController;
|
||||
@ -215,13 +215,7 @@ impl CalendarController {
|
||||
},
|
||||
}
|
||||
|
||||
let rendered = tmpl.render("calendar/index.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "calendar/index.html", &ctx)
|
||||
}
|
||||
|
||||
/// Handles the new event page route
|
||||
@ -234,13 +228,7 @@ impl CalendarController {
|
||||
ctx.insert("user", &user);
|
||||
}
|
||||
|
||||
let rendered = tmpl.render("calendar/new_event.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "calendar/new_event.html", &ctx)
|
||||
}
|
||||
|
||||
/// Handles the create event route
|
||||
@ -298,13 +286,9 @@ impl CalendarController {
|
||||
ctx.insert("user", &user);
|
||||
}
|
||||
|
||||
let rendered = tmpl.render("calendar/new_event.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
let result = render_template(&tmpl, "calendar/new_event.html", &ctx)?;
|
||||
|
||||
Ok(HttpResponse::InternalServerError().content_type("text/html").body(rendered))
|
||||
Ok(HttpResponse::InternalServerError().content_type("text/html").body(result.into_body()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ use chrono::{Utc, Duration};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::models::contract::{Contract, ContractStatus, ContractType, ContractStatistics, SignerStatus};
|
||||
use crate::utils::render_template;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ContractForm {
|
||||
@ -62,15 +63,7 @@ impl ContractController {
|
||||
|
||||
context.insert("draft_contracts", &draft_contracts);
|
||||
|
||||
let rendered = tmpl.render("contracts/index.html", &context)
|
||||
.map_err(|e| {
|
||||
log::error!("Template rendering error: {}", e);
|
||||
log::error!("Error details: {:?}", e);
|
||||
log::error!("Context: {:?}", context);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "contracts/index.html", &context)
|
||||
}
|
||||
|
||||
// Display the list of all contracts
|
||||
@ -89,15 +82,7 @@ impl ContractController {
|
||||
context.insert("contracts", &contracts_data);
|
||||
context.insert("filter", &"all");
|
||||
|
||||
let rendered = tmpl.render("contracts/contracts.html", &context)
|
||||
.map_err(|e| {
|
||||
log::error!("Template rendering error: {}", e);
|
||||
log::error!("Error details: {:?}", e);
|
||||
log::error!("Context: {:?}", context);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "contracts/contracts.html", &context)
|
||||
}
|
||||
|
||||
// Display the list of user's contracts
|
||||
@ -115,15 +100,7 @@ impl ContractController {
|
||||
|
||||
context.insert("contracts", &contracts_data);
|
||||
|
||||
let rendered = tmpl.render("contracts/my_contracts.html", &context)
|
||||
.map_err(|e| {
|
||||
log::error!("Template rendering error: {}", e);
|
||||
log::error!("Error details: {:?}", e);
|
||||
log::error!("Context: {:?}", context);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "contracts/my_contracts.html", &context)
|
||||
}
|
||||
|
||||
// Display a specific contract
|
||||
@ -146,15 +123,7 @@ impl ContractController {
|
||||
context.insert("contract", &contract_json);
|
||||
context.insert("user_has_signed", &false); // Mock data
|
||||
|
||||
let rendered = tmpl.render("contracts/contract_detail.html", &context)
|
||||
.map_err(|e| {
|
||||
log::error!("Template rendering error: {}", e);
|
||||
log::error!("Error details: {:?}", e);
|
||||
log::error!("Context: {:?}", context);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "contracts/contract_detail.html", &context)
|
||||
},
|
||||
None => {
|
||||
Ok(HttpResponse::NotFound().finish())
|
||||
@ -180,26 +149,18 @@ impl ContractController {
|
||||
|
||||
context.insert("contract_types", &contract_types);
|
||||
|
||||
let rendered = tmpl.render("contracts/create_contract.html", &context)
|
||||
.map_err(|e| {
|
||||
log::error!("Template rendering error: {}", e);
|
||||
log::error!("Error details: {:?}", e);
|
||||
log::error!("Context: {:?}", context);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "contracts/create_contract.html", &context)
|
||||
}
|
||||
|
||||
// Process the create contract form
|
||||
pub async fn create(
|
||||
tmpl: web::Data<Tera>,
|
||||
form: web::Form<ContractForm>,
|
||||
_tmpl: web::Data<Tera>,
|
||||
_form: web::Form<ContractForm>,
|
||||
) -> Result<HttpResponse> {
|
||||
// In a real application, we would save the contract to the database
|
||||
// For now, we'll just redirect to the contracts list
|
||||
|
||||
Ok(HttpResponse::Found().header("Location", "/contracts").finish())
|
||||
Ok(HttpResponse::Found().append_header(("Location", "/contracts")).finish())
|
||||
}
|
||||
|
||||
// Helper method to convert Contract to a JSON object for templates
|
||||
|
@ -3,10 +3,10 @@ use actix_session::Session;
|
||||
use chrono::{Utc, Duration};
|
||||
use serde::Deserialize;
|
||||
use tera::Tera;
|
||||
use std::error::Error; // Add this line
|
||||
|
||||
use crate::models::flow::{Flow, FlowStatus, FlowType, FlowStatistics, FlowStep, StepStatus, FlowLog};
|
||||
use crate::controllers::auth::Claims;
|
||||
use crate::utils::render_template;
|
||||
|
||||
pub struct FlowController;
|
||||
|
||||
@ -25,15 +25,7 @@ impl FlowController {
|
||||
ctx.insert("active_flows", &flows.iter().filter(|f| f.status == FlowStatus::InProgress).collect::<Vec<_>>());
|
||||
ctx.insert("stuck_flows", &flows.iter().filter(|f| f.status == FlowStatus::Stuck).collect::<Vec<_>>());
|
||||
|
||||
let rendered = tmpl.render("flows/index.html", &ctx)
|
||||
.map_err(|e| {
|
||||
log::error!("Template rendering error: {}", e);
|
||||
log::error!("Error details: {:?}", e);
|
||||
log::error!("Context: {:?}", ctx);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "flows/index.html", &ctx)
|
||||
}
|
||||
|
||||
/// Renders the flows list page
|
||||
@ -46,15 +38,7 @@ impl FlowController {
|
||||
ctx.insert("user", &user);
|
||||
ctx.insert("flows", &flows);
|
||||
|
||||
let rendered = tmpl.render("flows/flows.html", &ctx)
|
||||
.map_err(|e| {
|
||||
log::error!("Template rendering error: {}", e);
|
||||
log::error!("Error details: {:?}", e);
|
||||
log::error!("Context: {:?}", ctx);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "flows/flows.html", &ctx)
|
||||
}
|
||||
|
||||
/// Renders the flow detail page
|
||||
@ -76,29 +60,20 @@ impl FlowController {
|
||||
ctx.insert("user", &user);
|
||||
ctx.insert("flow", flow);
|
||||
|
||||
let rendered = tmpl.render("flows/flow_detail.html", &ctx)
|
||||
.map_err(|e| {
|
||||
log::error!("Template rendering error: {}", e);
|
||||
log::error!("Error details: {:?}", e);
|
||||
log::error!("Context: {:?}", ctx);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "flows/flow_detail.html", &ctx)
|
||||
} else {
|
||||
let mut ctx = tera::Context::new();
|
||||
ctx.insert("active_page", "flows");
|
||||
ctx.insert("error", "Flow not found");
|
||||
|
||||
let rendered = tmpl.render("error.html", &ctx)
|
||||
.map_err(|e| {
|
||||
log::error!("Template rendering error: {}", e);
|
||||
log::error!("Error details: {:?}", e);
|
||||
log::error!("Context: {:?}", ctx);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::NotFound().content_type("text/html").body(rendered))
|
||||
// For the error page, we'll use a special case to set the status code to 404
|
||||
match tmpl.render("error.html", &ctx) {
|
||||
Ok(content) => Ok(HttpResponse::NotFound().content_type("text/html").body(content)),
|
||||
Err(e) => {
|
||||
log::error!("Error rendering error template: {}", e);
|
||||
Err(actix_web::error::ErrorInternalServerError(format!("Error: {}", e)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,21 +85,13 @@ impl FlowController {
|
||||
ctx.insert("active_page", "flows");
|
||||
ctx.insert("user", &user);
|
||||
|
||||
let rendered = tmpl.render("flows/create_flow.html", &ctx)
|
||||
.map_err(|e| {
|
||||
log::error!("Template rendering error: {}", e);
|
||||
log::error!("Error details: {:?}", e);
|
||||
log::error!("Context: {:?}", ctx);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "flows/create_flow.html", &ctx)
|
||||
}
|
||||
|
||||
/// Handles the create flow form submission
|
||||
pub async fn create_flow(
|
||||
_form: web::Form<FlowForm>,
|
||||
session: Session
|
||||
_session: Session
|
||||
) -> impl Responder {
|
||||
// In a real application, we would create a new flow here
|
||||
// For now, just redirect to the flows list
|
||||
@ -149,15 +116,7 @@ impl FlowController {
|
||||
ctx.insert("user", &user);
|
||||
ctx.insert("flows", &my_flows);
|
||||
|
||||
let rendered = tmpl.render("flows/my_flows.html", &ctx)
|
||||
.map_err(|e| {
|
||||
log::error!("Template rendering error: {}", e);
|
||||
log::error!("Error details: {:?}", e);
|
||||
log::error!("Context: {:?}", ctx);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "flows/my_flows.html", &ctx)
|
||||
} else {
|
||||
Ok(HttpResponse::Found()
|
||||
.append_header(("Location", "/login"))
|
||||
|
@ -5,6 +5,7 @@ use serde_json::Value;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use chrono::{Utc, Duration};
|
||||
use crate::models::governance::{Proposal, Vote, ProposalStatus, VoteType, VotingResults};
|
||||
use crate::utils::render_template;
|
||||
|
||||
/// Controller for handling governance-related routes
|
||||
pub struct GovernanceController;
|
||||
@ -35,13 +36,7 @@ impl GovernanceController {
|
||||
let stats = Self::get_mock_statistics();
|
||||
ctx.insert("stats", &stats);
|
||||
|
||||
let rendered = tmpl.render("governance/index.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "governance/index.html", &ctx)
|
||||
}
|
||||
|
||||
/// Handles the proposal list page route
|
||||
@ -59,13 +54,7 @@ impl GovernanceController {
|
||||
let proposals = Self::get_mock_proposals();
|
||||
ctx.insert("proposals", &proposals);
|
||||
|
||||
let rendered = tmpl.render("governance/proposals.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "governance/proposals.html", &ctx)
|
||||
}
|
||||
|
||||
/// Handles the proposal detail page route
|
||||
@ -96,23 +85,18 @@ impl GovernanceController {
|
||||
let results = Self::get_mock_voting_results(&proposal_id);
|
||||
ctx.insert("results", &results);
|
||||
|
||||
let rendered = tmpl.render("governance/proposal_detail.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "governance/proposal_detail.html", &ctx)
|
||||
} else {
|
||||
// Proposal not found
|
||||
ctx.insert("error", "Proposal not found");
|
||||
let rendered = tmpl.render("error.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::NotFound().content_type("text/html").body(rendered))
|
||||
// For the error page, we'll use a special case to set the status code to 404
|
||||
match tmpl.render("error.html", &ctx) {
|
||||
Ok(content) => Ok(HttpResponse::NotFound().content_type("text/html").body(content)),
|
||||
Err(e) => {
|
||||
eprintln!("Error rendering error template: {}", e);
|
||||
Err(actix_web::error::ErrorInternalServerError(format!("Error: {}", e)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,18 +114,12 @@ impl GovernanceController {
|
||||
return Ok(HttpResponse::Found().append_header(("Location", "/login")).finish());
|
||||
}
|
||||
|
||||
let rendered = tmpl.render("governance/create_proposal.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "governance/create_proposal.html", &ctx)
|
||||
}
|
||||
|
||||
/// Handles the submission of a new proposal
|
||||
pub async fn submit_proposal(
|
||||
form: web::Form<ProposalForm>,
|
||||
_form: web::Form<ProposalForm>,
|
||||
tmpl: web::Data<Tera>,
|
||||
session: Session
|
||||
) -> Result<impl Responder> {
|
||||
@ -166,19 +144,13 @@ impl GovernanceController {
|
||||
let proposals = Self::get_mock_proposals();
|
||||
ctx.insert("proposals", &proposals);
|
||||
|
||||
let rendered = tmpl.render("governance/proposals.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "governance/proposals.html", &ctx)
|
||||
}
|
||||
|
||||
/// Handles the submission of a vote on a proposal
|
||||
pub async fn submit_vote(
|
||||
path: web::Path<String>,
|
||||
form: web::Form<VoteForm>,
|
||||
_form: web::Form<VoteForm>,
|
||||
tmpl: web::Data<Tera>,
|
||||
session: Session
|
||||
) -> Result<impl Responder> {
|
||||
@ -211,23 +183,18 @@ impl GovernanceController {
|
||||
let results = Self::get_mock_voting_results(&proposal_id);
|
||||
ctx.insert("results", &results);
|
||||
|
||||
let rendered = tmpl.render("governance/proposal_detail.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "governance/proposal_detail.html", &ctx)
|
||||
} else {
|
||||
// Proposal not found
|
||||
ctx.insert("error", "Proposal not found");
|
||||
let rendered = tmpl.render("error.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::NotFound().content_type("text/html").body(rendered))
|
||||
// For the error page, we'll use a special case to set the status code to 404
|
||||
match tmpl.render("error.html", &ctx) {
|
||||
Ok(content) => Ok(HttpResponse::NotFound().content_type("text/html").body(content)),
|
||||
Err(e) => {
|
||||
eprintln!("Error rendering error template: {}", e);
|
||||
Err(actix_web::error::ErrorInternalServerError(format!("Error: {}", e)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,13 +212,7 @@ impl GovernanceController {
|
||||
let votes = Self::get_mock_votes_for_user(1); // Assuming user ID 1 for mock data
|
||||
ctx.insert("votes", &votes);
|
||||
|
||||
let rendered = tmpl.render("governance/my_votes.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "governance/my_votes.html", &ctx)
|
||||
} else {
|
||||
// Redirect to login if not logged in
|
||||
Ok(HttpResponse::Found().append_header(("Location", "/login")).finish())
|
||||
|
@ -1,8 +1,10 @@
|
||||
use actix_web::{web, HttpResponse, Responder, Result};
|
||||
use actix_web::{web, Responder, Result};
|
||||
use actix_session::Session;
|
||||
use tera::Tera;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::utils::render_template;
|
||||
|
||||
/// Controller for handling home-related routes
|
||||
pub struct HomeController;
|
||||
|
||||
@ -24,13 +26,7 @@ impl HomeController {
|
||||
ctx.insert("user", &user);
|
||||
}
|
||||
|
||||
let rendered = tmpl.render("editor.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "editor.html", &ctx)
|
||||
}
|
||||
|
||||
/// Handles the home page route
|
||||
@ -43,13 +39,7 @@ impl HomeController {
|
||||
ctx.insert("user", &user);
|
||||
}
|
||||
|
||||
let rendered = tmpl.render("index.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "index.html", &ctx)
|
||||
}
|
||||
|
||||
/// Handles the about page route
|
||||
@ -62,13 +52,7 @@ impl HomeController {
|
||||
ctx.insert("user", &user);
|
||||
}
|
||||
|
||||
let rendered = tmpl.render("about.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "about.html", &ctx)
|
||||
}
|
||||
|
||||
/// Handles the contact page route
|
||||
@ -81,13 +65,7 @@ impl HomeController {
|
||||
ctx.insert("user", &user);
|
||||
}
|
||||
|
||||
let rendered = tmpl.render("contact.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "contact.html", &ctx)
|
||||
}
|
||||
|
||||
/// Handles form submissions from the contact page
|
||||
@ -112,13 +90,7 @@ impl HomeController {
|
||||
ctx.insert("user", &user);
|
||||
}
|
||||
|
||||
let rendered = tmpl.render("contact.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "contact.html", &ctx)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ use tera::Tera;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use crate::models::{User, Ticket, TicketComment, TicketStatus, TicketPriority};
|
||||
use crate::utils::render_template;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
@ -131,13 +132,7 @@ impl TicketController {
|
||||
]);
|
||||
|
||||
// Render the template
|
||||
let rendered = tmpl.render("tickets/list.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "tickets/list.html", &ctx)
|
||||
}
|
||||
|
||||
/// Shows the form for creating a new ticket
|
||||
@ -172,13 +167,7 @@ impl TicketController {
|
||||
]);
|
||||
|
||||
// Render the template
|
||||
let rendered = tmpl.render("tickets/new.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "tickets/new.html", &ctx)
|
||||
}
|
||||
|
||||
/// Creates a new ticket
|
||||
@ -285,13 +274,7 @@ impl TicketController {
|
||||
]);
|
||||
|
||||
// Render the template
|
||||
let rendered = tmpl.render("tickets/show.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "tickets/show.html", &ctx)
|
||||
}
|
||||
|
||||
/// Adds a comment to a ticket
|
||||
@ -443,12 +426,6 @@ impl TicketController {
|
||||
ctx.insert("my_tickets", &true);
|
||||
|
||||
// Render the template
|
||||
let rendered = tmpl.render("tickets/list.html", &ctx)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template rendering error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
||||
render_template(&tmpl, "tickets/list.html", &ctx)
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
use actix_web::{error, Error, HttpResponse};
|
||||
use chrono::{DateTime, Utc};
|
||||
use tera::{self, Function, Result, Value};
|
||||
use tera::{self, Context, Function, Tera, Value};
|
||||
|
||||
// Export modules
|
||||
pub mod redis_service;
|
||||
@ -7,6 +8,22 @@ pub mod redis_service;
|
||||
// Re-export for easier imports
|
||||
pub use redis_service::RedisCalendarService;
|
||||
|
||||
/// Error type for template rendering
|
||||
#[derive(Debug)]
|
||||
pub struct TemplateError {
|
||||
pub message: String,
|
||||
pub details: String,
|
||||
pub location: String,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for TemplateError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Template error in {}: {}", self.location, self.message)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for TemplateError {}
|
||||
|
||||
/// Registers custom Tera functions
|
||||
pub fn register_tera_functions(tera: &mut tera::Tera) {
|
||||
tera.register_function("now", NowFunction);
|
||||
@ -18,7 +35,7 @@ pub fn register_tera_functions(tera: &mut tera::Tera) {
|
||||
pub struct NowFunction;
|
||||
|
||||
impl Function for NowFunction {
|
||||
fn call(&self, args: &std::collections::HashMap<String, Value>) -> Result<Value> {
|
||||
fn call(&self, args: &std::collections::HashMap<String, Value>) -> tera::Result<Value> {
|
||||
let format = match args.get("format") {
|
||||
Some(val) => match val.as_str() {
|
||||
Some(s) => s,
|
||||
@ -43,7 +60,7 @@ impl Function for NowFunction {
|
||||
pub struct FormatDateFunction;
|
||||
|
||||
impl Function for FormatDateFunction {
|
||||
fn call(&self, args: &std::collections::HashMap<String, Value>) -> Result<Value> {
|
||||
fn call(&self, args: &std::collections::HashMap<String, Value>) -> tera::Result<Value> {
|
||||
let timestamp = match args.get("timestamp") {
|
||||
Some(val) => match val.as_i64() {
|
||||
Some(ts) => ts,
|
||||
@ -96,6 +113,50 @@ pub fn truncate_string(s: &str, max_length: usize) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
/// Renders a template with error handling
|
||||
///
|
||||
/// This function attempts to render a template and handles any errors by rendering
|
||||
/// the error template with detailed error information.
|
||||
pub fn render_template(
|
||||
tmpl: &Tera,
|
||||
template_name: &str,
|
||||
ctx: &Context,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
match tmpl.render(template_name, ctx) {
|
||||
Ok(content) => Ok(HttpResponse::Ok().content_type("text/html").body(content)),
|
||||
Err(e) => {
|
||||
// Log the error
|
||||
log::error!("Template rendering error: {}", e);
|
||||
log::error!("Error details: {:?}", e);
|
||||
log::error!("Context: {:?}", ctx);
|
||||
|
||||
// Create a context for the error template
|
||||
let mut error_ctx = Context::new();
|
||||
error_ctx.insert("error", &format!("Template rendering error: {}", e));
|
||||
error_ctx.insert("error_details", &format!("{:?}", e));
|
||||
error_ctx.insert("error_location", &template_name);
|
||||
|
||||
// Try to render the error template
|
||||
match tmpl.render("error.html", &error_ctx) {
|
||||
Ok(error_page) => {
|
||||
// Return the error page with a 500 status code
|
||||
Ok(HttpResponse::InternalServerError()
|
||||
.content_type("text/html")
|
||||
.body(error_page))
|
||||
}
|
||||
Err(render_err) => {
|
||||
// If we can't render the error template, log it and return a basic error
|
||||
log::error!("Error rendering error template: {}", render_err);
|
||||
Err(error::ErrorInternalServerError(format!(
|
||||
"Template rendering error: {}. Failed to render error page: {}",
|
||||
e, render_err
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -7,18 +7,44 @@
|
||||
<div class="col-md-8">
|
||||
<div class="card border-danger">
|
||||
<div class="card-header bg-danger text-white">
|
||||
<h4 class="mb-0"><i class="bi bi-exclamation-triangle-fill me-2"></i>Error</h4>
|
||||
<h4 class="mb-0"><i class="bi bi-exclamation-triangle-fill me-2"></i>Template Rendering Error</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Something went wrong</h5>
|
||||
<p class="card-text">{{ error }}</p>
|
||||
<h5 class="card-title">Something went wrong while rendering the template</h5>
|
||||
|
||||
<div class="alert alert-danger">
|
||||
<p class="mb-2"><strong>Error Message:</strong></p>
|
||||
<pre class="p-3 bg-light border rounded"><code>{{ error | default(value="Unknown error") }}</code></pre>
|
||||
</div>
|
||||
|
||||
{% if error_details is defined and error_details %}
|
||||
<div class="mt-3">
|
||||
<p class="mb-2"><strong>Error Details:</strong></p>
|
||||
<pre class="p-3 bg-light border rounded"><code>{{ error_details }}</code></pre>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if error_location is defined and error_location %}
|
||||
<div class="mt-3">
|
||||
<p class="mb-2"><strong>Error Location:</strong></p>
|
||||
<p>{{ error_location }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="alert alert-info mt-3">
|
||||
<p class="mb-0"><i class="bi bi-info-circle me-2"></i>This error is visible only in development mode. In production, a generic error page will be shown.</p>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<a href="/" class="btn btn-primary me-2">
|
||||
<i class="bi bi-house-door me-1"></i>Go to Home
|
||||
</a>
|
||||
<a href="javascript:history.back()" class="btn btn-outline-secondary">
|
||||
<a href="javascript:history.back()" class="btn btn-outline-secondary me-2">
|
||||
<i class="bi bi-arrow-left me-1"></i>Go Back
|
||||
</a>
|
||||
<button onclick="window.location.reload()" class="btn btn-outline-primary">
|
||||
<i class="bi bi-arrow-clockwise me-1"></i>Reload Page
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,14 +1,14 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}All Flows{% endblock %}
|
||||
{% block title %}Freezone Workflows{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/flows">Flows</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">All Flows</li>
|
||||
<li class="breadcrumb-item"><a href="/flows">Workflows</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Freezone Workflows</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
@ -16,11 +16,11 @@
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-8">
|
||||
<h1 class="display-5 mb-0">All Flows</h1>
|
||||
<h1 class="display-5 mb-0">Freezone Workflow Management</h1>
|
||||
</div>
|
||||
<div class="col-md-4 text-md-end">
|
||||
<a href="/flows/create" class="btn btn-primary">
|
||||
<i class="bi bi-plus-circle me-1"></i> Create New Flow
|
||||
<i class="bi bi-plus-circle me-1"></i> Create New Workflow
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@ -31,7 +31,7 @@
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form class="row g-3" action="/flows/list" method="get">
|
||||
<div class="col-md-4">
|
||||
<div class="col-md-3">
|
||||
<label for="status" class="form-label">Status</label>
|
||||
<select class="form-select" id="status" name="status">
|
||||
<option value="all" selected>All</option>
|
||||
@ -41,19 +41,34 @@
|
||||
<option value="cancelled">Cancelled</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label for="type" class="form-label">Type</label>
|
||||
<!-- Freezone filter - for UI demonstration only -->
|
||||
<div class="col-md-3">
|
||||
<label for="freezone" class="form-label">Freezone</label>
|
||||
<select class="form-select" id="freezone" name="freezone" disabled>
|
||||
<option value="all" selected>All Freezones</option>
|
||||
<option value="dubai_multi_commodities_centre">DMCC</option>
|
||||
<option value="dubai_international_financial_centre">DIFC</option>
|
||||
<option value="jebel_ali_free_zone">JAFZA</option>
|
||||
<option value="dubai_silicon_oasis">DSO</option>
|
||||
<option value="dubai_internet_city">DIC</option>
|
||||
<option value="dubai_media_city">DMC</option>
|
||||
<option value="abu_dhabi_global_market">ADGM</option>
|
||||
</select>
|
||||
<div class="form-text">Coming soon</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="type" class="form-label">Workflow Type</label>
|
||||
<select class="form-select" id="type" name="type">
|
||||
<option value="all" selected>All</option>
|
||||
<option value="company_registration">Company Registration</option>
|
||||
<option value="user_onboarding">User Onboarding</option>
|
||||
<option value="service_activation">Service Activation</option>
|
||||
<option value="company_registration">Company Incorporation</option>
|
||||
<option value="user_onboarding">KYC Verification</option>
|
||||
<option value="service_activation">License Activation</option>
|
||||
<option value="payment_processing">Payment Processing</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="col-md-3">
|
||||
<label for="search" class="form-label">Search</label>
|
||||
<input type="text" class="form-control" id="search" name="search" placeholder="Search flows...">
|
||||
<input type="text" class="form-control" id="search" name="search" placeholder="Search workflows...">
|
||||
</div>
|
||||
<div class="col-12 text-end">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
@ -79,14 +94,14 @@
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Flow Name</th>
|
||||
<th>Workflow Name</th>
|
||||
<th>Type</th>
|
||||
<th>Status</th>
|
||||
<th>Owner</th>
|
||||
<th>Assignee</th>
|
||||
<th>Progress</th>
|
||||
<th>Created</th>
|
||||
<th>Updated</th>
|
||||
<th>Current Step</th>
|
||||
<th>Initiated</th>
|
||||
<th>Last Updated</th>
|
||||
<th>Current Stage</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -120,21 +135,21 @@
|
||||
{{ current.name }}
|
||||
{% else %}
|
||||
{% if flow.status == 'Completed' %}
|
||||
All steps completed
|
||||
<span class="text-success">All stages completed</span>
|
||||
{% elif flow.status == 'Cancelled' %}
|
||||
Flow cancelled
|
||||
<span class="text-secondary">Workflow cancelled</span>
|
||||
{% else %}
|
||||
No active step
|
||||
<span class="text-muted">No active stage</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group">
|
||||
<a href="/flows/{{ flow.id }}" class="btn btn-sm btn-primary">
|
||||
<a href="/flows/{{ flow.id }}" class="btn btn-sm btn-primary" title="View Details">
|
||||
<i class="bi bi-eye"></i>
|
||||
</a>
|
||||
{% if flow.status == 'In Progress' %}
|
||||
<a href="/flows/{{ flow.id }}#advance" class="btn btn-sm btn-success">
|
||||
<a href="/flows/{{ flow.id }}#advance" class="btn btn-sm btn-success" title="Advance to Next Stage">
|
||||
<i class="bi bi-arrow-right"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
@ -146,7 +161,11 @@
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-center">No flows found matching your criteria.</p>
|
||||
<div class="text-center py-4">
|
||||
<i class="bi bi-search display-1 text-muted"></i>
|
||||
<p class="lead mt-3">No workflows found matching your criteria.</p>
|
||||
<p class="text-muted">Try adjusting your filters or create a new workflow.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user