├── .gitignore ├── README.md ├── accounts ├── __init__.py ├── admin.py ├── apps.py ├── forms.py ├── managers.py ├── migrations │ ├── 0001_initial.py │ └── __init__.py ├── models.py ├── templates │ └── accounts │ │ ├── login.html │ │ └── register.html ├── tests.py ├── urls.py └── views.py ├── common ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ └── __init__.py ├── models.py ├── tests.py └── views.py ├── events ├── __init__.py ├── admin.py ├── apps.py ├── forms.py ├── migrations │ ├── 0001_initial.py │ ├── 0002_idea.py │ ├── 0003_ideaupvote.py │ └── __init__.py ├── models.py ├── templates │ └── events │ │ └── event_detail.html ├── tests.py ├── urls.py └── views.py ├── hackogi ├── __init__.py ├── asgi.py ├── settings.py ├── urls.py ├── views.py └── wsgi.py ├── manage.py └── templates ├── base.html ├── header.html └── home.html /.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | db.sqlite3 3 | **/__pycache__/ 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hackathon Management Platform 2 | 3 | By https://t.me/JR_TwitGram 4 | -------------------------------------------------------------------------------- /accounts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rahmonov/hackogi/c272e7d323df6b88b4e070d361565565414e580e/accounts/__init__.py -------------------------------------------------------------------------------- /accounts/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin 3 | from django.contrib.auth import get_user_model 4 | 5 | 6 | User = get_user_model() 7 | 8 | 9 | class UserAdmin(DjangoUserAdmin): 10 | ordering = ("pk",) 11 | list_display = ( 12 | "email", 13 | "first_name", 14 | "last_name", 15 | "is_staff", 16 | "is_active", 17 | ) 18 | 19 | 20 | admin.site.register(User, UserAdmin) 21 | -------------------------------------------------------------------------------- /accounts/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AccountsConfig(AppConfig): 5 | default_auto_field = "django.db.models.BigAutoField" 6 | name = "accounts" 7 | -------------------------------------------------------------------------------- /accounts/forms.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.forms import AuthenticationForm, UserCreationForm 2 | from django.forms import TextInput, EmailInput, PasswordInput 3 | from accounts.models import CustomUser 4 | 5 | 6 | class CustomLoginForm(AuthenticationForm): 7 | def __init__(self, *args, **kwargs): 8 | super(CustomLoginForm, self).__init__(*args, **kwargs) 9 | self.fields['username'].widget = TextInput(attrs={ 10 | 'class': 'form-control', 11 | 'placeholder': 'Enter Your Username' 12 | }) 13 | self.fields['password'].widget = PasswordInput(attrs={ 14 | 'class': 'form-control', 15 | 'placeholder': 'Enter Your Password' 16 | }) 17 | 18 | class RegisterForm(UserCreationForm): 19 | def __init__(self, *args, **kwargs): 20 | super(RegisterForm, self).__init__(*args, **kwargs) 21 | self.fields['email'].widget = EmailInput(attrs={ 22 | 'class': 'form-control', 23 | 'placeholder': 'Enter Your Email' 24 | }) 25 | self.fields['password1'].widget = PasswordInput(attrs={ 26 | 'class': 'form-control', 27 | 'placeholder': 'Enter Your Password', 28 | 'id': 'password1' 29 | }) 30 | self.fields['password2'].widget = PasswordInput(attrs={ 31 | 'class': 'form-control', 32 | 'placeholder': 'Enter Your Password Confirmation', 33 | 'id': 'password2' 34 | }) 35 | 36 | class Meta: 37 | model = CustomUser 38 | fields = ( 39 | "email", 40 | "password1", 41 | "password2" 42 | ) 43 | -------------------------------------------------------------------------------- /accounts/managers.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.base_user import BaseUserManager 2 | from django.utils.translation import gettext_lazy as _ 3 | 4 | 5 | class CustomUserManager(BaseUserManager): 6 | """ 7 | Custom user model manager where email is the unique identifiers 8 | for authentication instead of usernames. 9 | """ 10 | def create_user(self, email, password, **extra_fields): 11 | """ 12 | Create and save a user with the given email and password. 13 | """ 14 | if not email: 15 | raise ValueError(_("The Email must be set")) 16 | email = self.normalize_email(email) 17 | user = self.model(email=email, **extra_fields) 18 | user.set_password(password) 19 | user.save() 20 | return user 21 | 22 | def create_superuser(self, email, password, **extra_fields): 23 | """ 24 | Create and save a SuperUser with the given email and password. 25 | """ 26 | extra_fields.setdefault("is_staff", True) 27 | extra_fields.setdefault("is_superuser", True) 28 | extra_fields.setdefault("is_active", True) 29 | 30 | if extra_fields.get("is_staff") is not True: 31 | raise ValueError(_("Superuser must have is_staff=True.")) 32 | if extra_fields.get("is_superuser") is not True: 33 | raise ValueError(_("Superuser must have is_superuser=True.")) 34 | return self.create_user(email, password, **extra_fields) 35 | 36 | -------------------------------------------------------------------------------- /accounts/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 5.0.6 on 2024-06-16 11:15 2 | 3 | import django.utils.timezone 4 | from django.db import migrations, models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | initial = True 10 | 11 | dependencies = [ 12 | ("auth", "0012_alter_user_first_name_max_length"), 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name="CustomUser", 18 | fields=[ 19 | ( 20 | "id", 21 | models.BigAutoField( 22 | auto_created=True, 23 | primary_key=True, 24 | serialize=False, 25 | verbose_name="ID", 26 | ), 27 | ), 28 | ("password", models.CharField(max_length=128, verbose_name="password")), 29 | ( 30 | "last_login", 31 | models.DateTimeField( 32 | blank=True, null=True, verbose_name="last login" 33 | ), 34 | ), 35 | ( 36 | "is_superuser", 37 | models.BooleanField( 38 | default=False, 39 | help_text="Designates that this user has all permissions without explicitly assigning them.", 40 | verbose_name="superuser status", 41 | ), 42 | ), 43 | ( 44 | "email", 45 | models.EmailField( 46 | max_length=254, unique=True, verbose_name="email address" 47 | ), 48 | ), 49 | ( 50 | "first_name", 51 | models.CharField(max_length=150, verbose_name="first name"), 52 | ), 53 | ( 54 | "last_name", 55 | models.CharField(max_length=150, verbose_name="last name"), 56 | ), 57 | ("is_staff", models.BooleanField(default=False)), 58 | ("is_active", models.BooleanField(default=True)), 59 | ( 60 | "date_joined", 61 | models.DateTimeField(default=django.utils.timezone.now), 62 | ), 63 | ( 64 | "groups", 65 | models.ManyToManyField( 66 | blank=True, 67 | help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.", 68 | related_name="user_set", 69 | related_query_name="user", 70 | to="auth.group", 71 | verbose_name="groups", 72 | ), 73 | ), 74 | ( 75 | "user_permissions", 76 | models.ManyToManyField( 77 | blank=True, 78 | help_text="Specific permissions for this user.", 79 | related_name="user_set", 80 | related_query_name="user", 81 | to="auth.permission", 82 | verbose_name="user permissions", 83 | ), 84 | ), 85 | ], 86 | options={ 87 | "verbose_name": "User", 88 | "verbose_name_plural": "Users", 89 | }, 90 | ), 91 | ] 92 | -------------------------------------------------------------------------------- /accounts/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rahmonov/hackogi/c272e7d323df6b88b4e070d361565565414e580e/accounts/migrations/__init__.py -------------------------------------------------------------------------------- /accounts/models.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin 2 | from django.db import models 3 | from django.utils import timezone 4 | from django.utils.translation import gettext_lazy as _ 5 | 6 | from accounts.managers import CustomUserManager 7 | from events.models import IdeaUpvote 8 | 9 | 10 | class CustomUser(AbstractBaseUser, PermissionsMixin): 11 | email = models.EmailField(_("email address"), unique=True) 12 | 13 | first_name = models.CharField(_("first name"), max_length=150) 14 | last_name = models.CharField(_("last name"), max_length=150) 15 | 16 | is_staff = models.BooleanField(default=False) 17 | is_active = models.BooleanField(default=True) 18 | 19 | date_joined = models.DateTimeField(default=timezone.now) 20 | 21 | USERNAME_FIELD = "email" 22 | REQUIRED_FIELDS = ["first_name", "last_name"] 23 | 24 | objects = CustomUserManager() 25 | 26 | class Meta: 27 | verbose_name = _("User") 28 | verbose_name_plural = _("Users") 29 | 30 | def __str__(self): 31 | return f"{self.first_name} {self.last_name}" 32 | 33 | def likes_idea(self, idea_id): 34 | return IdeaUpvote.objects.filter(user=self, idea_id=idea_id) 35 | -------------------------------------------------------------------------------- /accounts/templates/accounts/login.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %} Login Page {% endblock title %} 4 | 5 | {% block content %} 6 | 7 |
8 |
9 |
10 |
11 | Sample image 13 |
14 |
15 |

Sign in

16 |
17 | {% csrf_token %} 18 | 19 | {% for field in form %} 20 |
21 | 22 | {{ field }} 23 | {% if field.errors %} 24 |
25 | {% for error in field.errors %} 26 | {{ error }} 27 | {% endfor %} 28 |
29 | {% endif %} 30 |
31 | {% endfor %} 32 | {% if form.non_field_errors %} 33 |
34 | {% for error in form.non_field_errors %} 35 | {{ error }} 36 | {% endfor %} 37 |
38 | {% endif %} 39 |
40 | 41 |
42 |
43 |
44 |
45 |
46 |
47 | {% endblock content %} -------------------------------------------------------------------------------- /accounts/templates/accounts/register.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %} Register Page {% endblock title %} 4 | 5 | {% block content %} 6 | 12 |
13 |
14 |

Sign up

15 |
16 | {% csrf_token %} 17 | 18 | 19 | {% for field in form %} 20 |
21 | 22 | {{ field }} 23 | 24 | {% if field.id_for_label == 'password1' %} 25 |
    26 |
  • Your password can’t be too similar to your other personal information.
  • 27 |
  • Your password must contain at least 8 characters.
  • 28 |
  • Your password can’t be a commonly used password.
  • 29 |
  • Your password can’t be entirely numeric.
  • 30 |
31 | {% endif %} 32 | 33 |
34 | 35 | {% if field.errors %} 36 |
37 | {% for error in field.errors %} 38 | {{ error }} 39 | {% endfor %} 40 |
41 | {% endif %} 42 | {% endfor %} 43 | 44 | 45 | Already have account? 46 |
47 |
48 |
49 | 50 | 51 | 92 | {% endblock content %} -------------------------------------------------------------------------------- /accounts/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /accounts/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from accounts.views import LoginView, logout_view, RegisterView 4 | 5 | app_name = "accounts" 6 | urlpatterns = [ 7 | path("register/", RegisterView.as_view(), name="register"), 8 | path("login/", LoginView.as_view(), name="login"), 9 | path("logout/", logout_view, name="logout-view"), 10 | ] 11 | 12 | -------------------------------------------------------------------------------- /accounts/views.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth import authenticate, login, logout 2 | from django.shortcuts import render, redirect 3 | from django.views import View 4 | 5 | from accounts.forms import CustomLoginForm, RegisterForm 6 | 7 | 8 | class RegisterView(View): 9 | def get(self, request): 10 | form = RegisterForm() 11 | return render(request, "accounts/register.html", context={"form": form}) 12 | 13 | def post(self, request): 14 | form = RegisterForm(request.POST) 15 | if form.is_valid(): 16 | form.save() 17 | return redirect("accounts:login") 18 | return render(request, "accounts/register.html", context={"form": form}) 19 | 20 | 21 | class LoginView(View): 22 | def get(self, request): 23 | form = CustomLoginForm() 24 | return render(request, "accounts/login.html", context={"form": form}) 25 | 26 | def post(self, request): 27 | form = CustomLoginForm(request, request.POST) 28 | 29 | if form.is_valid(): 30 | username = form.cleaned_data["username"] 31 | password = form.cleaned_data["password"] 32 | user = authenticate(request, username=username, password=password) 33 | 34 | if user: 35 | login(request, user) 36 | return redirect("home") 37 | 38 | return render(request, "accounts/login.html", context={"form": form}) 39 | 40 | def logout_view(request): 41 | logout(request) 42 | return redirect("home") 43 | -------------------------------------------------------------------------------- /common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rahmonov/hackogi/c272e7d323df6b88b4e070d361565565414e580e/common/__init__.py -------------------------------------------------------------------------------- /common/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /common/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class CommonConfig(AppConfig): 5 | default_auto_field = "django.db.models.BigAutoField" 6 | name = "common" 7 | -------------------------------------------------------------------------------- /common/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rahmonov/hackogi/c272e7d323df6b88b4e070d361565565414e580e/common/migrations/__init__.py -------------------------------------------------------------------------------- /common/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | class BaseModel(models.Model): 4 | created_at = models.DateTimeField(auto_now_add=True) 5 | updated_at = models.DateTimeField(auto_now=True) 6 | 7 | class Meta: 8 | abstract = True 9 | 10 | -------------------------------------------------------------------------------- /common/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /common/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /events/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rahmonov/hackogi/c272e7d323df6b88b4e070d361565565414e580e/events/__init__.py -------------------------------------------------------------------------------- /events/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from .models import Event, Idea, IdeaUpvote 4 | 5 | 6 | class EventAdmin(admin.ModelAdmin): 7 | list_display = ( 8 | "title", 9 | "organizer", 10 | "start_date", 11 | "end_date", 12 | "is_approved", 13 | ) 14 | 15 | 16 | class IdeaAdmin(admin.ModelAdmin): 17 | pass 18 | 19 | class IdeaUpvoteAdmin(admin.ModelAdmin): 20 | pass 21 | 22 | admin.site.register(Event, EventAdmin) 23 | admin.site.register(Idea, IdeaAdmin) 24 | admin.site.register(IdeaUpvote, IdeaUpvoteAdmin) 25 | -------------------------------------------------------------------------------- /events/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class EventsConfig(AppConfig): 5 | default_auto_field = "django.db.models.BigAutoField" 6 | name = "events" 7 | -------------------------------------------------------------------------------- /events/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | from events.models import Idea 4 | 5 | 6 | class CreateIdeaForm(forms.ModelForm): 7 | class Meta: 8 | model = Idea 9 | fields = ( 10 | "title", 11 | "overview", 12 | ) 13 | 14 | def __init__(self, *args, **kwargs): 15 | super().__init__(*args, **kwargs) 16 | self.fields['title'].widget = forms.TextInput(attrs={ 17 | 'class': 'form-control', 18 | 'placeholder': 'Idea Title' 19 | }) 20 | self.fields['overview'].widget = forms.Textarea(attrs={ 21 | 'class': 'form-control', 22 | 'placeholder': 'Idea Overview' 23 | }) 24 | -------------------------------------------------------------------------------- /events/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 5.0.6 on 2024-06-16 11:46 2 | 3 | import django.db.models.deletion 4 | from django.conf import settings 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name="Event", 19 | fields=[ 20 | ( 21 | "id", 22 | models.BigAutoField( 23 | auto_created=True, 24 | primary_key=True, 25 | serialize=False, 26 | verbose_name="ID", 27 | ), 28 | ), 29 | ("created_at", models.DateTimeField(auto_now_add=True)), 30 | ("updated_at", models.DateTimeField(auto_now=True)), 31 | ("title", models.CharField(max_length=255, verbose_name="title")), 32 | ("overview", models.TextField(verbose_name="overview")), 33 | ("start_date", models.DateTimeField(verbose_name="start date")), 34 | ("end_date", models.DateTimeField(verbose_name="end date")), 35 | ("is_approved", models.BooleanField(default=False)), 36 | ( 37 | "organizer", 38 | models.ForeignKey( 39 | on_delete=django.db.models.deletion.CASCADE, 40 | related_name="events", 41 | related_query_name="event", 42 | to=settings.AUTH_USER_MODEL, 43 | ), 44 | ), 45 | ], 46 | options={ 47 | "abstract": False, 48 | }, 49 | ), 50 | ] 51 | -------------------------------------------------------------------------------- /events/migrations/0002_idea.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 5.0.6 on 2024-07-07 08:50 2 | 3 | import django.db.models.deletion 4 | from django.conf import settings 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ("events", "0001_initial"), 12 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name="Idea", 18 | fields=[ 19 | ( 20 | "id", 21 | models.BigAutoField( 22 | auto_created=True, 23 | primary_key=True, 24 | serialize=False, 25 | verbose_name="ID", 26 | ), 27 | ), 28 | ("created_at", models.DateTimeField(auto_now_add=True)), 29 | ("updated_at", models.DateTimeField(auto_now=True)), 30 | ("title", models.CharField(max_length=255, verbose_name="title")), 31 | ("overview", models.TextField(verbose_name="overview")), 32 | ( 33 | "event", 34 | models.ForeignKey( 35 | on_delete=django.db.models.deletion.CASCADE, 36 | related_name="ideas", 37 | related_query_name="idea", 38 | to="events.event", 39 | ), 40 | ), 41 | ( 42 | "owner", 43 | models.ForeignKey( 44 | on_delete=django.db.models.deletion.CASCADE, 45 | related_name="ideas", 46 | related_query_name="idea", 47 | to=settings.AUTH_USER_MODEL, 48 | ), 49 | ), 50 | ], 51 | options={ 52 | "abstract": False, 53 | }, 54 | ), 55 | ] 56 | -------------------------------------------------------------------------------- /events/migrations/0003_ideaupvote.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 5.0.6 on 2024-07-07 10:04 2 | 3 | import django.db.models.deletion 4 | from django.conf import settings 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ("events", "0002_idea"), 12 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name="IdeaUpvote", 18 | fields=[ 19 | ( 20 | "id", 21 | models.BigAutoField( 22 | auto_created=True, 23 | primary_key=True, 24 | serialize=False, 25 | verbose_name="ID", 26 | ), 27 | ), 28 | ("created_at", models.DateTimeField(auto_now_add=True)), 29 | ("updated_at", models.DateTimeField(auto_now=True)), 30 | ( 31 | "idea", 32 | models.ForeignKey( 33 | on_delete=django.db.models.deletion.CASCADE, 34 | related_name="upvotes", 35 | related_query_name="upvote", 36 | to="events.idea", 37 | ), 38 | ), 39 | ( 40 | "user", 41 | models.ForeignKey( 42 | on_delete=django.db.models.deletion.CASCADE, 43 | related_name="upvotes", 44 | related_query_name="upvote", 45 | to=settings.AUTH_USER_MODEL, 46 | ), 47 | ), 48 | ], 49 | options={ 50 | "unique_together": {("idea", "user")}, 51 | }, 52 | ), 53 | ] 54 | -------------------------------------------------------------------------------- /events/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rahmonov/hackogi/c272e7d323df6b88b4e070d361565565414e580e/events/migrations/__init__.py -------------------------------------------------------------------------------- /events/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.utils.translation import gettext_lazy as _ 3 | 4 | from common.models import BaseModel 5 | 6 | 7 | class Event(BaseModel): 8 | organizer = models.ForeignKey( 9 | "accounts.CustomUser", 10 | on_delete=models.CASCADE, 11 | related_name="events", 12 | related_query_name="event", 13 | ) 14 | 15 | title = models.CharField(_("title"), max_length=255) 16 | overview = models.TextField(_("overview")) 17 | 18 | start_date = models.DateTimeField(_("start date")) 19 | end_date = models.DateTimeField(_("end date")) 20 | 21 | is_approved = models.BooleanField(default=False) 22 | 23 | def __str__(self): 24 | return self.title 25 | 26 | 27 | class Idea(BaseModel): 28 | event = models.ForeignKey( 29 | Event, related_name="ideas", related_query_name="idea", on_delete=models.CASCADE 30 | ) 31 | owner = models.ForeignKey( 32 | "accounts.CustomUser", 33 | related_name="ideas", 34 | related_query_name="idea", 35 | on_delete=models.CASCADE, 36 | ) 37 | title = models.CharField(_("title"), max_length=255) 38 | overview = models.TextField(_("overview")) 39 | 40 | def __str__(self): 41 | return self.title 42 | 43 | 44 | class IdeaUpvote(BaseModel): 45 | idea = models.ForeignKey( 46 | Idea, 47 | related_name="upvotes", 48 | related_query_name="upvote", 49 | on_delete=models.CASCADE, 50 | ) 51 | user = models.ForeignKey( 52 | "accounts.CustomUser", 53 | related_name="upvotes", 54 | related_query_name="upvote", 55 | on_delete=models.CASCADE, 56 | ) 57 | 58 | class Meta: 59 | unique_together = ("idea", "user",) 60 | 61 | def __str__(self): 62 | return f"{self.user} likes {self.idea.title}" 63 | -------------------------------------------------------------------------------- /events/templates/events/event_detail.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% block title %} Event Detail Page {% endblock title %} 3 | 4 | {% block content %} 5 | 6 |
7 |
8 |
9 | *** 11 |
12 |
13 |

{{ event.title }}

14 | 25 |
26 |
27 | 28 | 78 | 79 |
80 | 85 | {% endblock %} 86 | -------------------------------------------------------------------------------- /events/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /events/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from events.views import EventDetailView, CreateEventIdeaView, UpvoteIdeaView 4 | 5 | app_name = "events" 6 | urlpatterns = [ 7 | path("/", EventDetailView.as_view(), name="event-detail"), 8 | path("/ideas/", CreateEventIdeaView.as_view(), name="create-idea"), 9 | path("/ideas//", UpvoteIdeaView.as_view(), name="upvote-idea"), 10 | ] 11 | -------------------------------------------------------------------------------- /events/views.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.mixins import LoginRequiredMixin 2 | from django.db.models import Exists, OuterRef 3 | from django.http.response import HttpResponse 4 | from django.shortcuts import redirect, render 5 | from django.views import View 6 | 7 | from events.forms import CreateIdeaForm 8 | from events.models import Event, Idea, IdeaUpvote 9 | 10 | 11 | class EventDetailView(View): 12 | def get(self, request, event_id): 13 | try: 14 | event = Event.objects.get(pk=event_id) 15 | except Event.DoesNotExist: 16 | return HttpResponse("Event does not exist") 17 | 18 | ideas = event.ideas.annotate( 19 | is_liked=Exists( 20 | IdeaUpvote.objects.filter(user=request.user, idea=OuterRef("pk")) 21 | ) 22 | ) 23 | context = {"event": event, "idea_form": CreateIdeaForm(), "ideas": ideas} 24 | 25 | return render(request, "events/event_detail.html", context=context) 26 | 27 | 28 | class CreateEventIdeaView(LoginRequiredMixin, View): 29 | def post(self, request, event_id): 30 | try: 31 | event = Event.objects.get(pk=event_id) 32 | except Event.DoesNotExist: 33 | return HttpResponse("Event does not exist") 34 | 35 | form = CreateIdeaForm(request.POST) 36 | 37 | if form.is_valid(): 38 | Idea.objects.create( 39 | owner=request.user, 40 | event=event, 41 | title=form.cleaned_data["title"], 42 | overview=form.cleaned_data["overview"], 43 | ) 44 | 45 | return redirect("events:event-detail", event_id=event.id) 46 | 47 | 48 | class UpvoteIdeaView(LoginRequiredMixin, View): 49 | def post(self, request, event_id, idea_id): 50 | try: 51 | idea = Idea.objects.get(id=idea_id, event__id=event_id) 52 | except Idea.DoesNotExist: 53 | return HttpResponse("Idea does not exist") 54 | 55 | IdeaUpvote.objects.create(idea=idea, user=request.user) 56 | 57 | return redirect("events:event-detail", event_id=event_id) 58 | -------------------------------------------------------------------------------- /hackogi/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rahmonov/hackogi/c272e7d323df6b88b4e070d361565565414e580e/hackogi/__init__.py -------------------------------------------------------------------------------- /hackogi/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for hackogi project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/5.0/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hackogi.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /hackogi/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for hackogi project. 3 | 4 | Generated by 'django-admin startproject' using Django 5.0.6. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/5.0/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/5.0/ref/settings/ 11 | """ 12 | 13 | from pathlib import Path 14 | 15 | # Build paths inside the project like this: BASE_DIR / 'subdir'. 16 | BASE_DIR = Path(__file__).resolve().parent.parent 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = 'django-insecure-_6h(2&47$x*k&b^vb($p@y^57pkz1(60ab+l%g+h@kj#!g1mjk' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = [] 29 | 30 | AUTH_USER_MODEL = "accounts.CustomUser" 31 | 32 | # Application definition 33 | 34 | INSTALLED_APPS = [ 35 | 'django.contrib.admin', 36 | 'django.contrib.auth', 37 | 'django.contrib.contenttypes', 38 | 'django.contrib.sessions', 39 | 'django.contrib.messages', 40 | 'django.contrib.staticfiles', 41 | "accounts", 42 | "common", 43 | "events", 44 | ] 45 | 46 | MIDDLEWARE = [ 47 | 'django.middleware.security.SecurityMiddleware', 48 | 'django.contrib.sessions.middleware.SessionMiddleware', 49 | 'django.middleware.common.CommonMiddleware', 50 | 'django.middleware.csrf.CsrfViewMiddleware', 51 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 52 | 'django.contrib.messages.middleware.MessageMiddleware', 53 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 54 | ] 55 | 56 | ROOT_URLCONF = 'hackogi.urls' 57 | 58 | TEMPLATES = [ 59 | { 60 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 61 | 'DIRS': [(BASE_DIR / 'templates')], 62 | 'APP_DIRS': True, 63 | 'OPTIONS': { 64 | 'context_processors': [ 65 | 'django.template.context_processors.debug', 66 | 'django.template.context_processors.request', 67 | 'django.contrib.auth.context_processors.auth', 68 | 'django.contrib.messages.context_processors.messages', 69 | ], 70 | }, 71 | }, 72 | ] 73 | 74 | WSGI_APPLICATION = 'hackogi.wsgi.application' 75 | 76 | 77 | # Database 78 | # https://docs.djangoproject.com/en/5.0/ref/settings/#databases 79 | 80 | DATABASES = { 81 | 'default': { 82 | 'ENGINE': 'django.db.backends.sqlite3', 83 | 'NAME': BASE_DIR / 'db.sqlite3', 84 | } 85 | } 86 | 87 | 88 | # Password validation 89 | # https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators 90 | 91 | AUTH_PASSWORD_VALIDATORS = [ 92 | { 93 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 94 | }, 95 | { 96 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 97 | }, 98 | { 99 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 100 | }, 101 | { 102 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 103 | }, 104 | ] 105 | 106 | 107 | # Internationalization 108 | # https://docs.djangoproject.com/en/5.0/topics/i18n/ 109 | 110 | LANGUAGE_CODE = 'en-us' 111 | 112 | TIME_ZONE = 'UTC' 113 | 114 | USE_I18N = True 115 | 116 | USE_TZ = True 117 | 118 | 119 | # Static files (CSS, JavaScript, Images) 120 | # https://docs.djangoproject.com/en/5.0/howto/static-files/ 121 | 122 | STATIC_URL = 'static/' 123 | 124 | # Default primary key field type 125 | # https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field 126 | 127 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' 128 | -------------------------------------------------------------------------------- /hackogi/urls.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.urls import path, include 3 | 4 | from hackogi.views import home_page 5 | 6 | urlpatterns = [ 7 | path("", home_page, name="home"), 8 | path("events/", include("events.urls", namespace="events")), 9 | path("accounts/", include("accounts.urls", namespace="accounts")), 10 | path('admin/', admin.site.urls), 11 | ] 12 | -------------------------------------------------------------------------------- /hackogi/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from django.utils import timezone 3 | 4 | from events.models import Event 5 | 6 | 7 | def home_page(request): 8 | now = timezone.now() 9 | active_hackathons = Event.objects.filter( 10 | is_approved=True, start_date__lt=now, end_date__gt=now 11 | ) 12 | past_hackathons = Event.objects.filter(is_approved=True, end_date__lt=now) 13 | upcoming_hackathons = Event.objects.filter(is_approved=True, start_date__gt=now) 14 | 15 | return render( 16 | request, 17 | "home.html", 18 | context={ 19 | "active_hackathons": active_hackathons, 20 | "upcoming_hackathons": upcoming_hackathons, 21 | "past_hackathons": past_hackathons, 22 | }, 23 | ) 24 | -------------------------------------------------------------------------------- /hackogi/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for hackogi project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/5.0/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hackogi.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hackogi.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% block title %}{% endblock title %} 5 | 6 | 7 | 8 | 9 | 10 | {% include "header.html" %} 11 |
12 | {% block content %}{% endblock content %} 13 |
14 | 15 | 16 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /templates/header.html: -------------------------------------------------------------------------------- 1 | 32 | -------------------------------------------------------------------------------- /templates/home.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% block title %} Home Page {% endblock title %} 3 | 4 | {% block content %} 5 | 6 |
7 |
8 |

Title of a longer featured blog post

9 |

Multiple lines of text that form the lede, informing new readers quickly and efficiently 10 | about what’s most interesting in this post’s contents.

11 |

Continue reading...

12 |
13 |
14 | 15 |

Active Hackathons

16 |
17 | {% for hackathon in active_hackathons %} 18 |
19 |
20 | hackathon image 22 |
23 |

{{ hackathon.title }}

24 | {{hackathon.overview}} 25 | 34 |
35 |
36 |
37 | {% endfor %} 38 |
39 | 40 |

Upcoming Hackathons

41 |
42 | {% for hackathon in upcoming_hackathons %} 43 |
44 |
45 | hackathon image 47 |
48 |

{{ hackathon.title }}

49 | {{hackathon.overview}} 50 | 59 |
60 |
61 |
62 | {% endfor %} 63 |
64 | 65 |

Past Hackathons

66 |
67 | {% for hackathon in past_hackathons %} 68 |
69 |
70 | hackathon image 72 |
73 |

{{ hackathon.title }}

74 | {{hackathon.overview}} 75 | 84 |
85 |
86 |
87 | {% endfor %} 88 |
89 | 90 | 91 | {% endblock %} 92 | --------------------------------------------------------------------------------