diff --git a/.vscode/settings.json b/.vscode/settings.json index 12901f9..ae378c2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,6 @@ { - "python.analysis.typeCheckingMode": "basic" + "python.analysis.typeCheckingMode": "basic", + "python.analysis.extraPaths": [ + "./equestlms" + ] } diff --git a/blog/migrations/0014_merge_20221021_0706.py b/blog/migrations/0014_merge_20221021_0706.py new file mode 100644 index 0000000..30c1b56 --- /dev/null +++ b/blog/migrations/0014_merge_20221021_0706.py @@ -0,0 +1,13 @@ +# Generated by Django 4.1.2 on 2022-10-21 07:06 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("blog", "0009_alter_blog_options_alter_category_options_and_more"), + ("blog", "0013_alter_blog_image"), + ] + + operations = [] diff --git a/config/urls.py b/config/urls.py index 9e21eff..9750138 100644 --- a/config/urls.py +++ b/config/urls.py @@ -16,6 +16,9 @@ path("accounts/", include("allauth.urls")), # Blog path("blog/", include("blog.urls", namespace="blog")), + # Course + path("course/", include("course.urls", namespace="course")), + # vVideos path("videos/", include("videos.urls", namespace="videos")), # Tutor path("tutor/", include("tutor.urls", namespace="tutor")), diff --git a/course/models.py b/course/models.py index 7be81dc..769e257 100644 --- a/course/models.py +++ b/course/models.py @@ -22,11 +22,14 @@ class CourseCategory(models.Model): is_top = models.BooleanField(default=False) courses = models.ManyToManyField("course.Course", blank=True) + class Meta: + verbose_name_plural = 'Course categories' + def __str__(self): return self.title def get_absolute_url(self): - return reverse("home:courses", kwargs={"slug": self.title}) + return reverse("home:course", kwargs={"slug": self.title}) def get_all_courses(self): courses_in_category = Course.objects.filter(category=self.title) @@ -40,9 +43,7 @@ class Course(TimeBasedModel): """ title = models.CharField(max_length=125, help_text="Title of the course") - category = models.ForeignKey( - CourseCategory, on_delete=models.CASCADE, default=1 - ) # Remove thhe default in develop branch + category = models.ForeignKey(CourseCategory, on_delete=models.CASCADE) # Remove thhe default in develop branch slug = models.SlugField(max_length=125, blank=True, null=True) overview = RichTextField() cover_image = models.ImageField(upload_to="./courses_cover_images/") @@ -68,6 +69,7 @@ def __str__(self) -> str: def save(self, *args, **kwargs): uuid_start = str(uuid.uuid1()).split("-", 1)[0] + print(uuid_start) if not self.pk: self.slug = slugify(self.title) + "-" + uuid_start @@ -78,7 +80,7 @@ def get_absolute_url(self): @property def tutor_courses_count(self): - return Course.objects.filter(tutors=self.tutors).count() + return Course.objects.filter(tutor=self.tutor).count() @property def student_courses_count(self): diff --git a/course/signals.py b/course/signals.py index 9b825e4..aea3fcf 100644 --- a/course/signals.py +++ b/course/signals.py @@ -12,7 +12,7 @@ def create_new_course_classroom(sender, instance, **kwargs): if instance.is_new is True: ClassRoom.objects.create( - tutor=instance.tutors, course=Course.objects.get(slug=instance.slug) + tutor=instance.tutor, course=Course.objects.get(slug=instance.slug) ) instance.is_new = False instance.save() diff --git a/course/urls.py b/course/urls.py index f63f60c..91f95be 100644 --- a/course/urls.py +++ b/course/urls.py @@ -14,4 +14,9 @@ view=course_view.CourseDetailView.as_view(), name="course-detail", ), + path( + "handle-purchase//", + view=course_view.HandlePurchaseView.as_view(), + name="handle-purchase", + ), ] diff --git a/course/views.py b/course/views.py index 100f9a1..468590f 100644 --- a/course/views.py +++ b/course/views.py @@ -1,6 +1,11 @@ +from django.shortcuts import redirect from django.views.generic import DetailView, ListView - -from course.models import Course +from django.views import View +from .models import ClassRoom, Course +from django.core.mail import send_mail +from django.contrib.auth import get_user_model +from django.contrib import messages +User = get_user_model() class AvailableCourseListView(ListView): @@ -16,5 +21,41 @@ def get_queryset(self): class CourseDetailView(DetailView): model = Course - template_name = "course/course_detail.html" + template_name = "course/course-details.html" context_object_name = "course" + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + course = Course.objects.get(slug=self.kwargs.get('slug')) + print(course) + context['classroom'] = ClassRoom.objects.get(course=course) + print("Me", context) + return super().get_context_data(**kwargs) + + +class HandlePurchaseView(View): + """ + Sends user details to admin admin and displays purchase status to user + """ + + def get(self, request, slug): + course = Course.objects.get(slug=slug) + if request.user.is_authenticated: + user = User.objects.get(pk=request.user.pk) + # Email admin + admin_email_details = { + 'subject': 'COURSE PURCHASE NOTIFICATION', + # type: ignore + # type: ignore + 'message': f'A user with name {user} made a purchase request. \n User details are as follows: \n Email: {user.email}', + 'recipient_list': ['solomonuche42@gmail.com'], + 'from_email': 'equestlms@equestlms.com' + + } + send_mail(subject=admin_email_details['subject'], message=admin_email_details["message"], + from_email=admin_email_details['from_email'], recipient_list=admin_email_details['recipient_list']) # type: ignore + # display message to user + messages.add_message(request, messages.INFO, + 'Thank you for learning with Equest, your purchase request has been sent.') + + return redirect(course) diff --git a/equestlms/templates/course/course-details.html b/equestlms/templates/course/course-details.html new file mode 100644 index 0000000..09442ff --- /dev/null +++ b/equestlms/templates/course/course-details.html @@ -0,0 +1,682 @@ +{% extends "base.html" %} +{% load static %} +{% block body %} + + +
+ + + + + + +
+
+ +
+ + +
+
+
+
+
+

{{classroom}}

+

{{ course.title }}

+ {{course.overview | safe}} +
+
+
+ + img + +
+
+
+ {{ course.tutor}} +
+

{{ course.tutor.bio }}

+
+
+ + + + + + 4.5 + (15) +
+
+ {{course.category}} +
+
+
+ +

12+ Lesson

+
+
+ +

9hr 30min

+
+
+ +

32 students enrolled

+
+
+
+ +
+ +
+ +
+
+
+
+
+ + +
+ + +
+
+
Overview
+
Course Description
+ {{course.overview|safe}} +
What you'll learn
+ +
+
+ + + + + + + +
+
+
About the instructor
+
+
+
+ + img + +
+
+
{{course.tutor}} +
+

{{course.tutor.bio}}

+
+
+
+ + + + + + 4.5 Instructor + Rating +
+
+
+
+ +

{{course.tutor_courses_count}} Courses

+
+
+ +

12+ Lesson

+
+
+ +

9hr 30min

+
+
+ +

270,866 students enrolled

+
+
+

{{course.tutor.bio}}

+

{{course.tutor.about}}

+ + + +

Available for:

+
    +
  • 1. Full Time Office Work
  • +
  • 2. Remote Work
  • +
  • 3. Freelance
  • +
  • 4. Contract
  • +
  • 5. Worldwide
  • +
+
+
+ + + +
+
+
Reviews
+
+
+
+ + img + +
+
+
John Doe +
+

UX/UI Designer

+
+
+
+ + + + + + 4.5 Instructor + Rating +
+
+

“ This is the second Photoshop course I have + completed with Cristian. Worth every penny and recommend it + highly. To get the most out of this course, its best to to take + the Beginner to Advanced course first. The sound and video + quality is of a good standard. Thank you Cristian. “

+ + Reply +
+
+ + + +
+
+
Post A comment
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+
+
+
+
+

${{course.price | floatformat:2}} +

+

$99.00 50% off

+
+
+ +
+ Share +
+ +
+ Buy Now +
+
+
+
+
+
+ + + + + + +
+
+
+

Includes

+ +
+
    +
  • 11 hours on-demand video
  • +
  • 69 downloadable resources
  • +
  • Full lifetime access
  • +
  • Access on mobile and TV
  • +
  • Assignments
  • +
  • Certificate of Completion
  • +
+
+
+ + + +
+
+
+

Includes

+ +
+
    +
  • Enrolled: 32 students
  • +
  • Duration: 20 hours
  • +
  • Chapters: 15
  • +
  • Video: 12 hours
  • +
  • Level: Beginner
  • +
+
+
+ + +
+
+
+
+ +
+ + + + +{% endblock body %} + +{% block bottom_js %} + + + + + + + + + + + + + + + + + + + + + + +{% endblock bottom_js %} diff --git a/equestlms/templates/pages/home.html b/equestlms/templates/pages/home.html index b9f9db7..38bc1d4 100644 --- a/equestlms/templates/pages/home.html +++ b/equestlms/templates/pages/home.html @@ -1,427 +1,515 @@ {% extends "base.html" %} {% load static %} {% block body %} - -
-
-
-
-
-
-
The Leader in Online Learning
-

Engaging & Accessible Online Courses For All

-

Own your future learning new skills online

-
- -
-

Trusted by over 15K Users
worldwide since 2022

-
-
-

1000+

-
-
-

4.4

- - - - - -
-
+ +
+
+
+
+
+
+
The Leader in Online Learning
+

Engaging & Accessible Online Courses For All

+

Own your future learning new skills online

+
+ -
-
- + +
+
+

Trusted by over 15K Users
worldwide since 2022

+
+
+

1000+

+
+
+

4.4

+ + + + +
-
- -
-
-
-
-
-
-
-
-
- -
-
-

10K

-

Online Courses

-
-
-
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
- -
-
-

200+

-

Expert Tutors

-
-
-
+
+

10K

+

Online Courses

-
-
-
-
-
- -
-
-

6K+

-

Ceritified Courses

-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
- -
-
-

60K +

-

Online Students

-
-
-
+
+

200+

+

Expert Tutors

-
- - - -
-
-
-
- Favourite Course -

Top Category

-
-
- All Categories +
+
+
+
+
+ +
+
+

6K+

+

Ceritified Courses

+
+
-
-

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Eget aenean accumsan bibendum gravida maecenas augue elementum et neque. Suspendisse imperdiet.

-
-
- +
+
+
+
+ - -
-
-
-
- What’s New -

Featured Courses

+ +
+
+
+
+ Favourite Course +

Top Category

+
+ +
+
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Eget aenean + accumsan bibendum gravida maecenas augue elementum et neque. Suspendisse + imperdiet.

+
+
- +
+ {% empty %} - -
-
-
-
- What’s New -

TRENDING COURSES

-
- -
-
-

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Eget aenean accumsan bibendum gravida maecenas augue elementum et neque. Suspendisse imperdiet.

-
-
+ + + +
+
+
+
+ What’s New +

Featured Courses

+
+ +
+
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Eget aenean accumsan bibendum gravida maecenas augue elementum et neque. + Suspendisse imperdiet.

+
+
+ + {% for course in featured %} +
+
+
+
+
+ + + +
+

₦{{ course.price }}

-
-
-
- -
-

{{ course.tutor }}

-

Tutor

-
-
-
- +
+
+
+
+ +
+

{{ course.tutor }} +

+

Tutor

-

{{ course.title }}

-
-
- -

13+ Lesson

-
-
- -

{{ course.hours_per_class }} Hours/Class

-
+
+
-
- - - - - - 4.0 (15) +
+

{{ course.title }}

+
+
+ +

12+ Lesson

+
+
+ +

{{ course.hours_per_class }} Hours/Class

- {% if user.is_authenticated and user.is_superuser %} - - {% elif user.is_authenticated %} - - {% else %} -
- Sign Up -
- {% endif %}
+
+ + + + + + 4.0 + (15) +
+ {% if user.is_authenticated and user.is_superuser %} + + + {% elif user.is_authenticated %} + + {% else %} +
+ Sign Up +
+ {% endif %}
- {% empty %} - {% if user.is_superuser %} -

No Featured Courses Yet!

- Add them now -
- {% endif %} - {% endfor %}
+
+
+ {% empty %} +
+ {% if user.is_superuser %} +

No Featured Courses Yet!

+ Add them now +
+ {% endif %} + {% endfor %} +
+
+
+ - -
-
-
-

Featured Instructor

-
-

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Eget aenean accumsan bibendum gravida maecenas augue elementum et neque. Suspendisse imperdiet.

+ +
+
+
+
+ What’s New +

TRENDING COURSES

+
+ +
+
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Eget aenean accumsan bibendum gravida maecenas augue elementum et neque. + Suspendisse imperdiet.

+
+
- +
+ {% empty %} + {% if user.is_superuser %} +

No Featured Courses Yet!

+ Add them now +
+ {% endif %} + {% endfor %} +
- -
-
-
-
-

Latest Blogs

-
-

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Eget aenean accumsan bibendum gravida maecenas augue elementum et neque. Suspendisse imperdiet.

-
-
+ +
+
+
+

Featured Instructor

+
+

Lorem ipsum dolor sit amet, consectetur adipiscing + elit. Eget aenean accumsan bibendum gravida maecenas augue elementum + et neque. Suspendisse imperdiet.

+
+
+
+ + - {% for blog in blogs %} -
-
- - - -
-
-
{{ blog.title }}
-

Marketing

-
- - {{ blog.created_at | timesince }} ago -
-
- {% endfor %} -
+
+
+ + + +
+
+
+
+

Latest Blogs

+
+

Lorem ipsum dolor sit amet, consectetur adipiscing + elit. Eget aenean accumsan bibendum gravida maecenas augue elementum + et neque. Suspendisse imperdiet.

+
+
+
+
- + {% endfor %} +
+
+
+
+ {% endblock body %}