116 lines
3.7 KiB
Python
116 lines
3.7 KiB
Python
from typing import Dict, Optional, List, Union
|
|
from datetime import datetime
|
|
from sqlalchemy.orm import Session
|
|
import re
|
|
from models.project import Project
|
|
from schemas.project import ProjectCreate, ProjectUpdate
|
|
|
|
def validate_github_link(github_link: str) -> bool:
|
|
"""
|
|
Validate GitHub repository URL format.
|
|
|
|
Args:
|
|
github_link: GitHub URL to validate
|
|
|
|
Returns:
|
|
bool: True if URL format is valid, False otherwise
|
|
"""
|
|
pattern = r'^https?:\/\/github\.com\/[\w-]+\/[\w-]+(?:\.git)?$'
|
|
return bool(re.match(pattern, github_link))
|
|
|
|
def validate_project_data(project_data: ProjectCreate) -> Dict[str, str]:
|
|
"""
|
|
Validate project data before creation.
|
|
|
|
Args:
|
|
project_data: Project data to validate
|
|
|
|
Returns:
|
|
Dict containing validation errors if any
|
|
"""
|
|
errors = {}
|
|
|
|
if len(project_data.title) > 255:
|
|
errors["title"] = "Title must not exceed 255 characters"
|
|
|
|
if not project_data.description:
|
|
errors["description"] = "Description is required"
|
|
|
|
if project_data.year < 2000 or project_data.year > datetime.now().year:
|
|
errors["year"] = "Invalid year"
|
|
|
|
if project_data.github_link and not validate_github_link(project_data.github_link):
|
|
errors["github_link"] = "Invalid GitHub repository URL"
|
|
|
|
return errors
|
|
|
|
def get_projects_by_technology(db: Session, technology: str) -> List[Project]:
|
|
"""
|
|
Get all projects that use a specific technology.
|
|
|
|
Args:
|
|
db: Database session
|
|
technology: Technology to search for
|
|
|
|
Returns:
|
|
List of projects using the specified technology
|
|
"""
|
|
return db.query(Project).filter(Project.technologies_used.ilike(f'%{technology}%')).all()
|
|
|
|
def get_department_statistics(db: Session) -> Dict[str, Dict[str, Union[int, float]]]:
|
|
"""
|
|
Get project statistics by department.
|
|
|
|
Args:
|
|
db: Database session
|
|
|
|
Returns:
|
|
Dictionary containing department statistics
|
|
"""
|
|
departments = db.query(Project.department).distinct().all()
|
|
stats = {}
|
|
|
|
for dept in departments:
|
|
dept_name = dept[0]
|
|
dept_projects = db.query(Project).filter(Project.department == dept_name).all()
|
|
|
|
published_count = sum(1 for p in dept_projects if p.is_published)
|
|
avg_grade = sum(float(p.grade) for p in dept_projects if p.grade) / len(dept_projects) if dept_projects else 0
|
|
|
|
stats[dept_name] = {
|
|
"total_projects": len(dept_projects),
|
|
"published_projects": published_count,
|
|
"average_grade": round(avg_grade, 2)
|
|
}
|
|
|
|
return stats
|
|
|
|
def format_project_response(project: Project) -> Dict[str, Any]:
|
|
"""
|
|
Format project data for API response.
|
|
|
|
Args:
|
|
project: Project object to format
|
|
|
|
Returns:
|
|
Formatted project data dictionary
|
|
"""
|
|
technologies = project.technologies_used.split(',') if project.technologies_used else []
|
|
|
|
return {
|
|
"id": project.id,
|
|
"title": project.title,
|
|
"description": project.description,
|
|
"student_name": project.student_name,
|
|
"supervisor_name": project.supervisor_name,
|
|
"department": project.department,
|
|
"year": project.year,
|
|
"status": project.status,
|
|
"technologies": technologies,
|
|
"github_link": project.github_link,
|
|
"documentation_link": project.documentation_link,
|
|
"grade": project.grade,
|
|
"is_published": project.is_published,
|
|
"created_at": project.created_at.isoformat() if project.created_at else None,
|
|
"updated_at": project.updated_at.isoformat() if project.updated_at else None
|
|
} |