Skip to content

Commit

Permalink
Update: Added K8s & Jenkins CI/CD
Browse files Browse the repository at this point in the history
  • Loading branch information
hoangsonww committed Oct 19, 2024
1 parent 7764c65 commit de6e990
Show file tree
Hide file tree
Showing 34 changed files with 840 additions and 104 deletions.
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
DJANGO_SECRET_KEY
DJANGO_DEBUG
DJANGO_ALLOWED_HOSTS
MONGO_DB_URI
MONGO_DB_USERNAME
MONGO_DB_PASSWORD
REDIS_LOCATION
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
/LMS-Backend/.env
/venv/
/node_modules/
/.env
1 change: 1 addition & 0 deletions LMS-Backend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ DJANGO_ALLOWED_HOSTS
MONGO_DB_URI
MONGO_DB_USERNAME
MONGO_DB_PASSWORD
REDIS_LOCATION
15 changes: 11 additions & 4 deletions LMS-Backend/LMSBackend/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
'corsheaders',
'drf_yasg',
'dj_rest_auth',
'dj_rest_auth.registration',
'allauth',
'allauth.account',
'allauth.socialaccount',
Expand Down Expand Up @@ -88,11 +89,17 @@

ROOT_URLCONF = 'LMSBackend.urls'

# CORS settings
CORS_ALLOW_ALL_ORIGINS = False # Disable allow all origins

# Explicitly allow specific origins
CORS_ALLOWED_ORIGINS = [
"http://localhost:4200",
'https://learning-management-system-fullstack.vercel.app', # Frontend hosted on Vercel
'https://fullstack-learning-management-system.netlify.app', # Backup Frontend hosted on Netlify
'http://localhost:4200', # Local development
]

CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_CREDENTIALS = True # Allow sending credentials like cookies and auth headers

TEMPLATES = [
{
Expand All @@ -115,7 +122,7 @@
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
'LOCATION': config('REDIS_LOCATION'),
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
}
Expand All @@ -142,7 +149,7 @@
'type': 'apiKey',
'in': 'header',
'name': 'Authorization',
'description': 'Enter your token in the format: Token {your_token}'
'description': 'Enter your token in the format: Bearer {your_token}'
}
},
'DEFAULT_API_KEY': 'Token ',
Expand Down
7 changes: 3 additions & 4 deletions LMS-Backend/LMSBackend/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@
openapi.Info(
title="Learning Management System API",
default_version='v1',
description="API documentation for the Learning Management System",
terms_of_service="http://127.0.0.1:8000/swagger/",
contact=openapi.Contact(email="[email protected]"),
description="Comprehensive API documentation for the Learning Management System",
terms_of_service="https://moodify-emotion-music-app.vercel.app/terms-of-service",
contact=openapi.Contact(email="[email protected]", name="Learning Management System", url="https://moodify-emotion-music-app.vercel.app/"),
license=openapi.License(name="MIT License"),
),
public=True,
permission_classes=(permissions.AllowAny,),
)

urlpatterns = [
Expand Down
Binary file modified LMS-Backend/db.sqlite3
Binary file not shown.
2 changes: 1 addition & 1 deletion LMS-Backend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ djangorestframework==3.15.2
djangorestframework-simplejwt==5.3.1
djongo==1.2.31
dnspython==2.6.1
drf-yasg==1.21.7
drf-yasg==1.21.8
Faker==28.4.1
idna==3.8
inflection==0.5.1
Expand Down
2 changes: 2 additions & 0 deletions LMS-Frontend/app/src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import { CourseListComponent } from './components/course-list/course-list.compon
import { LessonListComponent } from './components/lesson-list/lesson-list.component';
import { EnrollmentListComponent } from './components/enrollment-list/enrollment-list.component';
import { ProgressListComponent } from './components/progress-list/progress-list.component';
import { RegisterComponent } from './auth/register/register.component';

export const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'login', component: LoginComponent },
{ path: 'register', component: RegisterComponent },
{ path: 'users', component: UserListComponent },
{ path: 'courses', component: CourseListComponent },
{ path: 'lessons', component: LessonListComponent },
Expand Down
59 changes: 59 additions & 0 deletions LMS-Frontend/app/src/app/auth/register/register.component.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
.register-container {
height: 80vh;
display: flex;
align-items: center;
justify-content: center;
margin-top: 0;
}

.form-label {
font-size: 1.1rem;
font-weight: 500;
margin-bottom: 0.5rem;
color: #333;
margin-right: 10px;
}

.form-control-lg {
height: calc(2rem + 2px);
padding: 0.75rem 1rem;
border-radius: 8px;
border: 1px solid #ccc;
transition: border-color 0.3s ease;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
margin-top: 5px;
font: inherit;
}

.form-control-lg:focus {
border-color: #007bff;
box-shadow: 0 0 5px rgba(0, 123, 255, 0.5);
}

.register-card {
max-width: 400px;
width: 100%;
border-radius: 12px;
border: none;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
padding: 20px;
}

.btn-primary {
font-weight: 600;
padding: 0.75rem 1rem;
font-size: 1rem;
transition: background-color 0.3s, transform 0.3s;
border-radius: 8px;
}

.btn-primary:hover {
background-color: #0056b3;
transform: scale(1.05);
}

.alert-danger {
font-size: 0.95rem;
padding: 12px;
border-radius: 8px;
}
61 changes: 61 additions & 0 deletions LMS-Frontend/app/src/app/auth/register/register.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<div class="register-container d-flex justify-content-center align-items-center">
<div class="card p-5 shadow-lg register-card">
<h2 class="text-center text-primary mb-4">Register</h2>
<form (ngSubmit)="register()">
<div class="form-group mb-3">
<label for="username" class="form-label">Username:</label>
<input
type="text"
id="username"
[(ngModel)]="username"
name="username"
class="form-control form-control-lg"
placeholder="Enter your username"
required
/>
</div>
<div class="form-group mb-3">
<label for="email" class="form-label">Email:</label>
<input
type="email"
id="email"
[(ngModel)]="email"
name="email"
class="form-control form-control-lg"
placeholder="Enter your email"
required
/>
</div>
<div class="form-group mb-3">
<label for="password1" class="form-label">Password:</label>
<input
type="password"
id="password1"
[(ngModel)]="password1"
name="password1"
class="form-control form-control-lg"
placeholder="Enter your password"
required
/>
</div>
<div class="form-group mb-3">
<label for="password2" class="form-label">Confirm Password:</label>
<input
type="password"
id="password2"
[(ngModel)]="password2"
name="password2"
class="form-control form-control-lg"
placeholder="Confirm your password"
required
/>
</div>
<button type="submit" class="btn btn-primary btn-lg w-100 mt-3">Register</button>

<!-- Display error message if any -->
<div *ngIf="errorMessage" class="alert alert-danger mt-4 text-center">
{{ errorMessage }}
</div>
</form>
</div>
</div>
33 changes: 33 additions & 0 deletions LMS-Frontend/app/src/app/auth/register/register.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '../../services/auth.service';
import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';

@Component({
selector: 'app-register',
standalone: true,
imports: [FormsModule, CommonModule],
templateUrl: './register.component.html',
styleUrls: ['./register.component.css']
})
export class RegisterComponent {
username: string = '';
email: string = '';
password1: string = '';
password2: string = '';
errorMessage: string = '';

constructor(private authService: AuthService, private router: Router) {}

register(): void {
this.authService.register(this.username, this.email, this.password1, this.password2).subscribe(
() => {
this.router.navigate(['/login']); // Redirect to login page after successful registration
},
(error) => {
this.errorMessage = error.error?.detail || 'Registration failed';
}
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,21 @@
border-radius: 15px;
margin: 15px;
}

.loading-overlay {
position: fixed; /* Cover the entire viewport */
top: 0;
left: 0;
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background-color: rgba(255, 255, 255, 0.8); /* Optional: light overlay effect */
z-index: 9999; /* Ensure it stays on top */
}

.spinner-border {
width: 3rem;
height: 3rem;
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,37 @@
<div class="container">
<h2 class="mb-4 text-primary text-center">Platform Overview</h2>

<!-- Chart Section -->
<!-- Chart Section (Always visible) -->
<div class="chart-section mb-5 mt-5">
<div class="chart-container">
<canvas id="courseChart" width="200" height="200"></canvas>
</div>
</div>

<h2 class="mb-4 text-primary text-center">Courses</h2>
<div *ngIf="errorMessage" class="alert alert-danger" style="text-align: center;">{{ errorMessage }}</div>
<div *ngIf="courses.length === 0 && !errorMessage" class="alert alert-info">No courses available.</div>
<!-- Loading Indicator for rest of the page -->
<div *ngIf="loading" class="loading-overlay">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>

<!-- Courses and Errors (only shown when loading is false) -->
<div *ngIf="!loading">
<h2 class="mb-4 text-primary text-center">Courses</h2>
<div *ngIf="errorMessage" class="alert alert-danger" style="text-align: center;">{{ errorMessage }}</div>
<div *ngIf="courses.length === 0 && !errorMessage" class="alert alert-info">No courses available.</div>

<!-- Course Cards Section -->
<div class="row justify-content-center">
<div class="col-md-6 col-lg-4 mb-4" *ngFor="let course of courses">
<div class="card shadow-lg h-100 rounded-custom p-3">
<div class="card-body d-flex flex-column justify-content-between">
<div>
<h4 class="card-title text-primary">{{ course.title }}</h4>
<p class="card-text text-muted">{{ course.description }}</p>
<hr>
<p class="card-text"><strong>Instructor:</strong> {{ formatInstructorName(course.instructor) }}</p>
<!-- Course Cards Section -->
<div class="row justify-content-center">
<div class="col-md-6 col-lg-4 mb-4" *ngFor="let course of courses">
<div class="card shadow-lg h-100 rounded-custom p-3">
<div class="card-body d-flex flex-column justify-content-between">
<div>
<h4 class="card-title text-primary">{{ course.title }}</h4>
<p class="card-text text-muted">{{ course.description }}</p>
<hr>
<p class="card-text"><strong>Instructor:</strong> {{ formatInstructorName(course.instructor) }}</p>
</div>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ Chart.register(...registerables);
export class CourseListComponent implements OnInit {
courses: any[] = [];
errorMessage: string = '';
loading: boolean = true; // Track loading state
chart: Chart<'pie'> | undefined;
private apiUrl = 'http://127.0.0.1:8000/api/';
private apiUrl = 'https://learning-management-system-fullstack.onrender.com/api/';
lessonsLength: number = 0;
enrollmentsLength: number = 0;

Expand All @@ -44,9 +45,11 @@ export class CourseListComponent implements OnInit {
this.courses = coursesData;
this.lessonsLength = lessonsData.length;
this.enrollmentsLength = enrollmentsData.length;
this.renderChart();
this.loading = false; // Stop loading after data fetching is complete
this.renderChart(); // Render the chart after data is fetched
},
(error) => {
this.loading = false; // Stop loading in case of error
if (error.status === 401) {
this.errorMessage = 'Unauthorized access. Please log in.';
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,21 @@
border-radius: 15px;
margin: 15px;
}

.loading-overlay {
position: fixed; /* Cover the entire viewport */
top: 0;
left: 0;
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background-color: rgba(255, 255, 255, 0.8); /* Optional: light overlay effect */
z-index: 9999; /* Ensure it stays on top */
}

.spinner-border {
width: 3rem;
height: 3rem;
}
Loading

0 comments on commit de6e990

Please sign in to comment.