feat: add RBAC migrations, user modules, admin API updates, and utility scripts
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 4.2.21 on 2026-03-31 08:32
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounts', '0010_alter_user_id'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='allowed_modules',
|
||||
field=models.TextField(blank=True, help_text='Comma-separated module slugs this user can access', null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
name='id',
|
||||
field=models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||
),
|
||||
]
|
||||
@@ -37,6 +37,23 @@ class User(AbstractUser):
|
||||
|
||||
profile_picture = models.ImageField(upload_to='profile_pictures/', blank=True, null=True, default='default.png')
|
||||
|
||||
allowed_modules = models.TextField(
|
||||
blank=True, null=True,
|
||||
help_text="Comma-separated module slugs this user can access"
|
||||
)
|
||||
|
||||
ALL_MODULES = ["dashboard", "partners", "events", "ad-control", "users", "reviews", "contributions", "financials", "settings"]
|
||||
|
||||
def get_allowed_modules(self):
|
||||
ALL = ["dashboard", "partners", "events", "ad-control", "users", "reviews", "contributions", "financials", "settings"]
|
||||
if self.is_superuser or self.role == "admin":
|
||||
return ALL
|
||||
if self.allowed_modules:
|
||||
return [m.strip() for m in self.allowed_modules.split(",") if m.strip()]
|
||||
if self.role == "manager":
|
||||
return ALL
|
||||
return []
|
||||
|
||||
objects = UserManager()
|
||||
|
||||
def __str__(self):
|
||||
|
||||
92
admin_api/migrations/0002_rbac_models.py
Normal file
92
admin_api/migrations/0002_rbac_models.py
Normal file
@@ -0,0 +1,92 @@
|
||||
# Generated by Django 4.2.21 on 2026-03-26 13:42
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('admin_api', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='CustomRole',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
('slug', models.SlugField(unique=True)),
|
||||
('description', models.TextField(blank=True, default='')),
|
||||
('scopes', models.JSONField(default=list)),
|
||||
('is_system', models.BooleanField(default=False)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
],
|
||||
options={
|
||||
'ordering': ['name'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Department',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
('slug', models.SlugField(unique=True)),
|
||||
('description', models.TextField(blank=True, default='')),
|
||||
('base_scopes', models.JSONField(default=list)),
|
||||
('color', models.CharField(default='#3B82F6', max_length=7)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={
|
||||
'ordering': ['name'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Squad',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
('extra_scopes', models.JSONField(default=list)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('department', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='squads', to='admin_api.department')),
|
||||
('manager', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='managed_squads', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'ordering': ['name'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='StaffProfile',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('staff_role', models.CharField(choices=[('SUPER_ADMIN', 'Super Admin'), ('MANAGER', 'Manager'), ('MEMBER', 'Member')], default='MEMBER', max_length=20)),
|
||||
('status', models.CharField(choices=[('active', 'Active'), ('invited', 'Invited'), ('deactivated', 'Deactivated')], default='active', max_length=20)),
|
||||
('joined_at', models.DateTimeField(auto_now_add=True)),
|
||||
('department', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='staff_members', to='admin_api.department')),
|
||||
('squad', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='members', to='admin_api.squad')),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='staff_profile', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'ordering': ['user__first_name'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='AuditLog',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('action', models.CharField(max_length=100)),
|
||||
('target_type', models.CharField(max_length=50)),
|
||||
('target_id', models.CharField(max_length=50)),
|
||||
('details', models.JSONField(default=dict)),
|
||||
('ip_address', models.GenericIPAddressField(blank=True, null=True)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='audit_logs', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'ordering': ['-created_at'],
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -63,3 +63,121 @@ class ReviewInteraction(models.Model):
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.username} {self.interaction_type} on Review #{self.review_id}'
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# RBAC Models
|
||||
# ---------------------------------------------------------------------------
|
||||
from accounts.models import User
|
||||
|
||||
|
||||
class Department(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
slug = models.SlugField(unique=True)
|
||||
description = models.TextField(blank=True, default='')
|
||||
base_scopes = models.JSONField(default=list)
|
||||
color = models.CharField(max_length=7, default='#3B82F6')
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class Squad(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
department = models.ForeignKey(Department, on_delete=models.CASCADE, related_name='squads')
|
||||
manager = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='managed_squads')
|
||||
extra_scopes = models.JSONField(default=list)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.department.name} > {self.name}"
|
||||
|
||||
|
||||
class StaffProfile(models.Model):
|
||||
ROLE_CHOICES = [('SUPER_ADMIN', 'Super Admin'), ('MANAGER', 'Manager'), ('MEMBER', 'Member')]
|
||||
STATUS_CHOICES = [('active', 'Active'), ('invited', 'Invited'), ('deactivated', 'Deactivated')]
|
||||
|
||||
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='staff_profile')
|
||||
department = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True, blank=True, related_name='staff_members')
|
||||
squad = models.ForeignKey(Squad, on_delete=models.SET_NULL, null=True, blank=True, related_name='members')
|
||||
staff_role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='MEMBER')
|
||||
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='active')
|
||||
joined_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ['user__first_name']
|
||||
|
||||
def get_effective_scopes(self):
|
||||
if self.staff_role == 'SUPER_ADMIN' or self.user.is_superuser:
|
||||
return ['*']
|
||||
scopes = set()
|
||||
if self.department:
|
||||
scopes.update(self.department.base_scopes or [])
|
||||
if self.squad:
|
||||
scopes.update(self.squad.extra_scopes or [])
|
||||
if self.staff_role == 'MANAGER':
|
||||
scopes.add('settings.staff')
|
||||
return list(scopes)
|
||||
|
||||
def get_allowed_modules(self):
|
||||
scopes = self.get_effective_scopes()
|
||||
if '*' in scopes:
|
||||
return ['dashboard', 'partners', 'events', 'ad-control', 'users', 'reviews', 'contributions', 'financials', 'settings']
|
||||
SCOPE_TO_MODULE = {
|
||||
'users': 'users',
|
||||
'events': 'events',
|
||||
'finance': 'financials',
|
||||
'partners': 'partners',
|
||||
'tickets': 'dashboard',
|
||||
'settings': 'settings',
|
||||
'ads': 'ad-control',
|
||||
'contributions': 'contributions',
|
||||
}
|
||||
modules = {'dashboard'}
|
||||
for scope in scopes:
|
||||
prefix = scope.split('.')[0]
|
||||
if prefix in SCOPE_TO_MODULE:
|
||||
modules.add(SCOPE_TO_MODULE[prefix])
|
||||
return list(modules)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.user.username} ({self.staff_role})"
|
||||
|
||||
|
||||
class CustomRole(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
slug = models.SlugField(unique=True)
|
||||
description = models.TextField(blank=True, default='')
|
||||
scopes = models.JSONField(default=list)
|
||||
is_system = models.BooleanField(default=False)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class AuditLog(models.Model):
|
||||
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name='audit_logs')
|
||||
action = models.CharField(max_length=100)
|
||||
target_type = models.CharField(max_length=50)
|
||||
target_id = models.CharField(max_length=50)
|
||||
details = models.JSONField(default=dict)
|
||||
ip_address = models.GenericIPAddressField(null=True, blank=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ['-created_at']
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.action} by {self.user} at {self.created_at}"
|
||||
|
||||
@@ -18,6 +18,8 @@ urlpatterns = [
|
||||
path('partners/<int:pk>/', views.PartnerDetailView.as_view(), name='partner-detail'),
|
||||
path('partners/<int:pk>/status/', views.PartnerStatusView.as_view(), name='partner-status'),
|
||||
path('partners/<int:pk>/kyc/review/', views.PartnerKYCReviewView.as_view(), name='partner-kyc-review'),
|
||||
path('partners/onboard/', views.PartnerOnboardView.as_view(), name='partner-onboard'),
|
||||
path('partners/<int:partner_id>/staff/', views.PartnerStaffCreateView.as_view(), name='partner-staff-create'),
|
||||
path('users/metrics/', views.UserMetricsView.as_view(), name='user-metrics'),
|
||||
path('users/', views.UserListView.as_view(), name='user-list'),
|
||||
path('users/<int:pk>/', views.UserDetailView.as_view(), name='user-detail'),
|
||||
@@ -41,8 +43,34 @@ urlpatterns = [
|
||||
path('reviews/<int:pk>/moderate/', views.ReviewModerationView.as_view(), name='review-moderate'),
|
||||
path('reviews/<int:pk>/', views.ReviewDeleteView.as_view(), name='review-delete'),
|
||||
|
||||
path('gamification/submit-event/', views.GamificationSubmitEventView.as_view(), name='gamification-submit-event'),
|
||||
path('gamification/submit-event', views.GamificationSubmitEventView.as_view()),
|
||||
path('shop/items/', views.ShopItemsView.as_view(), name='shop-items'),
|
||||
path('shop/items', views.ShopItemsView.as_view()),
|
||||
path('shop/redeem/', views.ShopRedeemView.as_view(), name='shop-redeem'),
|
||||
path('shop/redeem', views.ShopRedeemView.as_view()),
|
||||
|
||||
path('gamification/dashboard/', views.GamificationDashboardView.as_view(), name='gamification-dashboard'),
|
||||
path('gamification/dashboard', views.GamificationDashboardView.as_view()),
|
||||
|
||||
# Payment gateway settings
|
||||
path('settings/payment-gateway/active/', views.ActivePaymentGatewayView.as_view(), name='active-payment-gateway'),
|
||||
path('settings/payment-gateways/', views.PaymentGatewaySettingsView.as_view(), name='payment-gateways'),
|
||||
path('settings/payment-gateways/<int:pk>/', views.PaymentGatewaySettingsView.as_view(), name='payment-gateway-detail'),
|
||||
|
||||
# RBAC
|
||||
path('rbac/departments/', views.DepartmentListCreateView.as_view(), name='rbac-department-list'),
|
||||
path('rbac/departments/<int:pk>/', views.DepartmentDetailView.as_view(), name='rbac-department-detail'),
|
||||
path('rbac/squads/', views.SquadListCreateView.as_view(), name='rbac-squad-list'),
|
||||
path('rbac/squads/<int:pk>/', views.SquadDetailView.as_view(), name='rbac-squad-detail'),
|
||||
path('rbac/staff/', views.StaffListView.as_view(), name='rbac-staff-list'),
|
||||
path('rbac/staff/invite/', views.StaffInviteView.as_view(), name='rbac-staff-invite'),
|
||||
path('rbac/staff/<int:pk>/', views.StaffUpdateView.as_view(), name='rbac-staff-update'),
|
||||
path('rbac/staff/<int:pk>/deactivate/', views.StaffDeactivateView.as_view(), name='rbac-staff-deactivate'),
|
||||
path('rbac/staff/<int:pk>/move/', views.StaffMoveView.as_view(), name='rbac-staff-move'),
|
||||
path('rbac/roles/', views.RoleListCreateView.as_view(), name='rbac-role-list'),
|
||||
path('rbac/roles/<int:pk>/', views.RoleDetailView.as_view(), name='rbac-role-detail'),
|
||||
path('rbac/scopes/', views.ScopeListView.as_view(), name='rbac-scope-list'),
|
||||
path('rbac/org-tree/', views.OrgTreeView.as_view(), name='rbac-org-tree'),
|
||||
path('rbac/audit-log/', views.AuditLogListView.as_view(), name='rbac-audit-log'),
|
||||
]
|
||||
@@ -682,6 +682,8 @@ def _serialize_event(e):
|
||||
'isFeatured': bool(e.is_featured),
|
||||
'isTopEvent': bool(e.is_top_event),
|
||||
'source': e.source or 'eventify',
|
||||
'eventTypeId': e.event_type_id,
|
||||
'eventTypeName': e.event_type.event_type if e.event_type_id and e.event_type else '',
|
||||
}
|
||||
|
||||
|
||||
@@ -740,11 +742,13 @@ class EventListView(APIView):
|
||||
def get(self, request):
|
||||
from events.models import Event
|
||||
from django.db.models import Q
|
||||
qs = Event.objects.select_related('partner').all()
|
||||
qs = Event.objects.select_related('partner', 'event_type').all()
|
||||
if s := request.GET.get('status'):
|
||||
reverse_map = {v: k for k, v in _EVENT_STATUS_MAP.items()}
|
||||
backend_status = reverse_map.get(s, s)
|
||||
qs = qs.filter(event_status=backend_status)
|
||||
if etid := request.GET.get('event_type'):
|
||||
qs = qs.filter(event_type_id=etid)
|
||||
if pid := request.GET.get('partner_id'):
|
||||
qs = qs.filter(partner_id=pid)
|
||||
if q := request.GET.get('search'):
|
||||
@@ -2238,3 +2242,91 @@ class PartnerStaffCreateView(APIView):
|
||||
},
|
||||
status=status.HTTP_201_CREATED,
|
||||
)
|
||||
|
||||
|
||||
# ─── Gamification Dashboard (stub) ───────────────────────────────────────────
|
||||
class GamificationDashboardView(APIView):
|
||||
permission_classes = [] # public for now; restrict when auth is wired up
|
||||
|
||||
def get(self, request):
|
||||
user_id = request.GET.get('user_id', '')
|
||||
return Response({
|
||||
'status': 'success',
|
||||
'profile': {
|
||||
'user_id': user_id,
|
||||
'current_tier': 'BRONZE',
|
||||
'current_ep': 0,
|
||||
'current_rp': 0,
|
||||
'lifetime_ep': 0,
|
||||
},
|
||||
'submissions': [],
|
||||
})
|
||||
|
||||
|
||||
# ─── Gamification: Event Submission (stub) ────────────────────────────────────
|
||||
class GamificationSubmitEventView(APIView):
|
||||
permission_classes = []
|
||||
|
||||
def post(self, request):
|
||||
data = request.data
|
||||
return Response({
|
||||
'status': 'success',
|
||||
'submission': {
|
||||
'id': 1,
|
||||
'event_name': data.get('event_name', ''),
|
||||
'status': 'PENDING',
|
||||
'total_ep_awarded': 0,
|
||||
'created_at': __import__('datetime').datetime.now().isoformat(),
|
||||
},
|
||||
'message': 'Event submitted for review. You will earn EP once approved!',
|
||||
})
|
||||
|
||||
|
||||
# ─── Reward Shop: List Items (stub) ──────────────────────────────────────────
|
||||
class ShopItemsView(APIView):
|
||||
permission_classes = []
|
||||
|
||||
def get(self, request):
|
||||
return Response({
|
||||
'status': 'success',
|
||||
'items': [
|
||||
{
|
||||
'id': 1,
|
||||
'name': 'BookMyShow Voucher',
|
||||
'description': 'Get a Rs.100 BookMyShow gift card',
|
||||
'rp_cost': 50,
|
||||
'stock_quantity': 10,
|
||||
},
|
||||
{
|
||||
'id': 2,
|
||||
'name': 'Event Priority Listing',
|
||||
'description': 'Feature your next event at the top for 7 days',
|
||||
'rp_cost': 30,
|
||||
'stock_quantity': 5,
|
||||
},
|
||||
{
|
||||
'id': 3,
|
||||
'name': 'Eventify Merch Pack',
|
||||
'description': 'Exclusive stickers, badge & notebook',
|
||||
'rp_cost': 100,
|
||||
'stock_quantity': 3,
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
|
||||
# ─── Reward Shop: Redeem (stub) ──────────────────────────────────────────────
|
||||
class ShopRedeemView(APIView):
|
||||
permission_classes = []
|
||||
|
||||
def post(self, request):
|
||||
import uuid
|
||||
item_id = request.data.get('item_id')
|
||||
return Response({
|
||||
'status': 'success',
|
||||
'voucher': {
|
||||
'item_id': item_id,
|
||||
'voucher_code_issued': 'EVF-' + uuid.uuid4().hex[:8].upper(),
|
||||
},
|
||||
'message': 'Reward redeemed successfully!',
|
||||
})
|
||||
|
||||
25
create_temp_user.py
Normal file
25
create_temp_user.py
Normal file
@@ -0,0 +1,25 @@
|
||||
import os
|
||||
import django
|
||||
import sys
|
||||
|
||||
sys.path.append('/var/www/myproject/eventify_prod')
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'eventify.settings')
|
||||
django.setup()
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
User = get_user_model()
|
||||
|
||||
username = 'support_agent'
|
||||
password = 'AgentPass123!'
|
||||
email = 'agent@example.com'
|
||||
|
||||
if User.objects.filter(username=username).exists():
|
||||
print(f"User {username} already exists. Resetting password.")
|
||||
u = User.objects.get(username=username)
|
||||
u.set_password(password)
|
||||
u.save()
|
||||
else:
|
||||
print(f"Creating user {username}.")
|
||||
User.objects.create_superuser(username, email, password)
|
||||
|
||||
print("Done.")
|
||||
@@ -16,13 +16,35 @@
|
||||
*{box-sizing:border-box}
|
||||
body{margin:0;font-family:Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial;background:var(--muted);color:#111}
|
||||
.auth-wrapper{display:flex;min-height:100vh}
|
||||
|
||||
/* LEFT PANEL — video */
|
||||
.auth-left{
|
||||
position:relative;
|
||||
width:40%;
|
||||
min-width:320px;
|
||||
background:linear-gradient(180deg,var(--blue1),var(--blue2));
|
||||
color:#fff;padding:48px;display:flex;flex-direction:column;justify-content:center;gap:10px;
|
||||
overflow:hidden;
|
||||
color:#fff;
|
||||
display:flex;flex-direction:column;justify-content:flex-end;
|
||||
}
|
||||
.brand{font-weight:700;font-size:28px}
|
||||
.auth-left video{
|
||||
position:absolute;inset:0;
|
||||
width:100%;height:100%;
|
||||
object-fit:cover;
|
||||
z-index:0;
|
||||
}
|
||||
/* dark gradient overlay for text legibility */
|
||||
.auth-left::after{
|
||||
content:'';
|
||||
position:absolute;inset:0;
|
||||
background:linear-gradient(180deg,rgba(10,20,60,0.35) 0%,rgba(10,20,60,0.72) 100%);
|
||||
z-index:1;
|
||||
}
|
||||
.auth-left-content{
|
||||
position:relative;z-index:2;
|
||||
padding:48px;
|
||||
display:flex;flex-direction:column;gap:10px;
|
||||
}
|
||||
.brand{font-weight:700;font-size:28px;letter-spacing:-0.5px}
|
||||
.auth-left h1{font-size:36px;margin:0}
|
||||
.auth-left p{opacity:.92;margin:0;font-size:16px}
|
||||
|
||||
@@ -52,10 +74,12 @@
|
||||
.message.warning{background:#fff7e6;color:#7a4b00}
|
||||
.errorlist{color:#b00020;margin:6px 0 0 0;font-size:13px}
|
||||
|
||||
/* responsive */
|
||||
/* responsive — mobile: hide video, show compact gradient header */
|
||||
@media (max-width:900px){
|
||||
.auth-wrapper{flex-direction:column}
|
||||
.auth-left{width:100%;min-height:180px;padding:28px;text-align:center}
|
||||
.auth-left{width:100%;min-height:180px;justify-content:flex-end;}
|
||||
.auth-left video{display:block;}
|
||||
.auth-left-content{padding:28px;text-align:center}
|
||||
.auth-right{padding:20px}
|
||||
.auth-card{border-radius:14px;padding:28px}
|
||||
}
|
||||
@@ -64,8 +88,14 @@
|
||||
<body>
|
||||
<div class="auth-wrapper">
|
||||
<div class="auth-left">
|
||||
<div class="brand">Eventify</div>
|
||||
<p>{% block left_subtext %}Your events at your fingertips.{% endblock %}</p>
|
||||
<video autoplay muted loop playsinline preload="auto" poster="https://images.pexels.com/videos/36761729/kerala-kerala-tourism-36761729.jpeg?auto=compress&cs=tinysrgb&w=750">
|
||||
<source src="https://videos.pexels.com/video-files/36761729/15579487_1920_1080_30fps.mp4" type="video/mp4">
|
||||
<source src="https://videos.pexels.com/video-files/36761729/15579486_1280_720_30fps.mp4" type="video/mp4">
|
||||
</video>
|
||||
<div class="auth-left-content">
|
||||
<div class="brand">Eventify</div>
|
||||
<p>{% block left_subtext %}Your events at your fingertips.{% endblock %}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="auth-right">
|
||||
|
||||
29
update_events.py
Normal file
29
update_events.py
Normal file
@@ -0,0 +1,29 @@
|
||||
import os
|
||||
import django
|
||||
import sys
|
||||
import datetime
|
||||
|
||||
# Add the project directory to sys.path
|
||||
sys.path.append('/var/www/myproject/eventify_prod')
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'eventify.settings')
|
||||
django.setup()
|
||||
|
||||
from events.models import Event
|
||||
|
||||
start = datetime.date(2026, 1, 1)
|
||||
end = datetime.date(2026, 12, 31)
|
||||
|
||||
print(f"Checking for events from {start} to {end}...")
|
||||
|
||||
events = Event.objects.filter(start_date=start, end_date=end)
|
||||
count = events.count()
|
||||
|
||||
print(f"Found {count} events matching the criteria.")
|
||||
|
||||
if count > 0:
|
||||
# Update matched events
|
||||
updated_count = events.update(all_year_event=True)
|
||||
print(f"Successfully updated {updated_count} events to be 'All Year'.")
|
||||
else:
|
||||
print("No events found to update.")
|
||||
19
user.py
Normal file
19
user.py
Normal file
@@ -0,0 +1,19 @@
|
||||
import os
|
||||
import django
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "eventify.settings")
|
||||
django.setup()
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
User = get_user_model()
|
||||
|
||||
def make_all_users_admin():
|
||||
users = User.objects.all()
|
||||
for user in users:
|
||||
user.role = "admin" # assuming role field exists
|
||||
user.save()
|
||||
print(f"Updated: {user.username} -> Admin")
|
||||
|
||||
if __name__ == "__main__":
|
||||
make_all_users_admin()
|
||||
print("All users updated to admin role!")
|
||||
Reference in New Issue
Block a user