from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin, Group from django.db import models from django.utils.translation import gettext_lazy as _ import random from datetime import datetime, timedelta from django.utils import timezone from rest_framework_simplejwt.token_blacklist.models import BlacklistedToken, OutstandingToken import hashlib from django.contrib import admin from django.conf import settings import requests class UserManager(BaseUserManager): def create_user(self, phone, password=None): if not phone: raise ValueError('Users must have a phone number') user = self.model( phone=phone, ) user.set_password(password) user.save(using=self._db) return user def create_superuser(self, phone, password=None): user = self.create_user( phone=phone, ) user.is_staff = True user.is_superuser = True user.set_password(password) user.save(using=self._db) return user class User(AbstractBaseUser, PermissionsMixin): email = models.EmailField(max_length=255, verbose_name='ایمیل', blank=True, null=True) phone = models.CharField(max_length=12, verbose_name='شماره تماس', unique=True) first_name = models.CharField(max_length=50, blank=True, verbose_name='نام') last_name = models.CharField(max_length=50, blank=True, verbose_name='نام خانوادگی') profile_photo = models.ImageField(upload_to='profile_photos/', null=True, blank=True, verbose_name='عکس پروفایل') is_active = models.BooleanField(default=True, verbose_name='فعال بودن کاربر') is_staff = models.BooleanField(default=False, verbose_name='کارمند') gender_option = ( ('مرد', 'مرد'), ('زن', 'زن') ) gender = models.CharField(choices=gender_option, max_length=20, verbose_name='جنسیت') birth_date = models.DateField(blank=True, null=True) date_joined = models.DateTimeField(auto_now_add=True, verbose_name='تاریخ ثبتنام') otp_hash = models.CharField(max_length=64, null=True, blank=True, verbose_name='کد یک بار مصرف') otp_expiry = models.DateTimeField(null=True, blank=True, verbose_name='تاریخ تمام شدن کد یک بار مصرف') video_uploader = models.BooleanField(default=False, help_text='اپلود کننده ی ویدیویی اموزشی پنل ادمین', verbose_name='اپلودر اموزش') objects = UserManager() USERNAME_FIELD = 'phone' REQUIRED_FIELDS = [] # @property # def groups(self): # return None @property def full_name(self): if self.first_name and self.last_name: return f"{self.first_name} {self.last_name}" return None # @property # def user_permissions(self): # return None class Meta: verbose_name = 'کاربر' verbose_name_plural = 'کاربران' def _hash_otp(self, otp): return hashlib.sha256(otp.encode()).hexdigest() def set_otp(self): raw_otp = str(random.randint(100000, 999999)) self.otp_hash = self._hash_otp(raw_otp) self.otp_expiry = timezone.now() + timedelta(minutes=5) self.save() return raw_otp def clear_otp(self): self.otp_hash = None self.otp_expiry = None self.save() def verify_otp(self, otp_code): if self.otp_hash and self.otp_expiry > timezone.now(): return self.otp_hash == self._hash_otp(otp_code) return False def blacklist_user_tokens(self): try: tokens = OutstandingToken.objects.filter(user=self) for token in tokens: BlacklistedToken.objects.get_or_create(token=token) except Exception as e: print(f"block list error: {e}") def __str__(self): if self.first_name and self.last_name: return f'{self.first_name} {self.last_name}' else: return self.phone def get_name(self): if self.first_name and self.last_name: return f'{self.first_name} {self.last_name}' else: return self.phone class ShopModel(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='shop', verbose_name='کاربر') shop_name = models.CharField(max_length=100, verbose_name='نام فروشگاه') shop_description = models.TextField(verbose_name='توضیحات فروشگاه') def __str__(self): return f"{self.user.phone} - {self.shop_name}" class Meta: verbose_name = 'فروشگاه' verbose_name_plural = 'فروشگاه ها' class UserAddressModel(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='address', verbose_name='کاربر') name = models.CharField(max_length=30, verbose_name='نام ادرس') address = models.TextField(verbose_name='ادرس کامل') postal_code = models.CharField(max_length=10, verbose_name='کد پستی') phone = models.CharField(max_length=11, verbose_name='شماره تماس برای ارسال', help_text='شماره تماس کاربر و شماره ی ارسالی میتواند متفاوت باشد') city = models.CharField(max_length=30, verbose_name='شهر') province = models.CharField(max_length=30, verbose_name='استان') for_me = models.BooleanField(default=False, verbose_name='برای خود کاربر') is_main = models.BooleanField(default=False, verbose_name='ادرس اصلی کاربر') def __str__(self): return f"{self.user.phone}, {self.name}" class Meta: verbose_name = 'ادرس کاربر' verbose_name_plural = 'ادرس های کاربر' import os import json from pywebpush import webpush, WebPushException class PushSubscription(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) endpoint = models.TextField(unique=True) keys = models.JSONField() created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f'{self.user} push' class Meta: verbose_name = 'اشتراک نوتیفیکیشن' verbose_name_plural = 'اشتراک های نوتیفیکیشن' def send_notif(self, title, body, icon): payload = { "title": 'فروشگاه هی ملز', "body": body, "icon": 'https://api.heymlz.com' + icon, "image": 'https://api.heymlz.com' + icon, } print(payload) try: webpush( subscription_info={ "endpoint": self.endpoint, "keys": self.keys }, data=json.dumps(payload), vapid_private_key=settings.VAPID_PRIVATE_KEY, vapid_claims={ "sub": "mailto:admin@example.com" } ) except WebPushException as ex: print("Failed to send notification:", ex) @classmethod def send_group_notification(cls, user, title, body): payload = { "title": 'فروشگاه هی ملز', "body": body, "icon": '' } subscriptions = PushSubscription.objects.filter(user=user) for sub in subscriptions: try: webpush( subscription_info={ "endpoint": sub.endpoint, "keys": sub.keys }, data=json.dumps(payload), vapid_private_key=settings.VAPID_PRIVATE_KEY, vapid_claims={ "sub": "mailto:admin@example.com", 'aud': 'https://mamalizz-cooked.vercel.app' } ) except WebPushException as ex: print(f"Failed to send notification to {sub.user}:", ex) class NotifBaseModel(models.Model): title = models.CharField(max_length=50) content = models.TextField() image = models.ImageField() created_at = models.DateTimeField(auto_now_add=True) is_read = models.BooleanField(default=False) class Meta: abstract = True def __str__(self): return self.title class NewsModel(NotifBaseModel): def notif_type(self): return 'NEWS' class UserNotificationModel(NotifBaseModel): user = models.ForeignKey(User, on_delete=models.CASCADE) def notif_type(self): return 'USER_NOTIF' def get_location_from_ip(ip_address): try: response = requests.get(f"http://ip-api.com/json/{ip_address}") data = response.json() if data["status"] == "success": return data['country'], data['regionName'], data['city'], data.get('zip', 'ناموجود'), data['lat'], data['lon'], data['isp'] else: print("Error fetching data: ", data["message"]) return None except Exception as e: print(f"An error occurred: {e}") return None class SecurityBreachAttemptModel(models.Model): ip_address = models.CharField(max_length=100, verbose_name="آدرس آی‌پی") country = models.CharField(max_length=101, verbose_name="کشور", blank=True, null=True) region_name = models.CharField(max_length=102, verbose_name="منطقه", blank=True, null=True) city = models.CharField(max_length=103, verbose_name="شهر", blank=True, null=True) zip_code = models.CharField(max_length=104, verbose_name="کد پستی", blank=True, null=True) lon = models.CharField(max_length=105, verbose_name="طول جغرافیایی", blank=True, null=True) lat = models.CharField(max_length=106, verbose_name="عرض جغرافیایی", blank=True, null=True) isp = models.CharField(max_length=107, verbose_name="ارائه‌دهنده اینترنت (ISP)", blank=True, null=True) viewd = models.BooleanField(default=False, verbose_name='تماشا شده') created_at = models.DateTimeField(auto_now_add=True, verbose_name='شروع حمله') trys = models.IntegerField(default=0, verbose_name='تعداد تلاش ها') def save(self, *args, **kwargs): if not self.id: location_data = get_location_from_ip(self.ip_address) if location_data: self.country, self.region_name, self.city, self.zip_code, self.lat, self.lon, self.isp = location_data super().save(*args, **kwargs) def __str__(self): return f'تلاش نفوذ از {self.ip_address} در {self.city}, {self.country}' class Meta: verbose_name = "تلاش نفوذ" verbose_name_plural = "تلاش‌های نفوذ" # class NotifModel(models.Model): # subject = models.CharField(max_length=100) # description = models.TextField() # def __str__(self): # return f'{self.subject[:30]}' from product.models import ProductModel class UserFavorites(models.Model): user = models.OneToOneField(User, verbose_name=_('User'), on_delete=models.CASCADE) products = models.ManyToManyField(ProductModel, verbose_name=_('Likes'), blank=True,) def __str__(self): return f'{self.user} likes' class Meta: verbose_name = _("User Favorites") verbose_name_plural = _("Users Favorites")