From 81031a71b2943903f653fa0fafb4cfe03935917b Mon Sep 17 00:00:00 2001 From: S Rahul Badami Date: Sat, 29 Aug 2020 11:49:47 +0530 Subject: [PATCH] Added Stripe Integration/ Bug Hunt Winner Selection Logic & Winner Payment Logic --- bugheist/settings.py | 8 +- bugheist/urls.py | 12 +- website/admin.py | 34 +- website/migrations/0059_transaction_wallet.py | 35 + website/migrations/0060_wallet_account_id.py | 18 + website/migrations/0061_payment.py | 23 + website/migrations/0062_company_is_active.py | 18 + website/migrations/0063_auto_20200826_0351.py | 28 + website/migrations/0064_issue_hunt.py | 19 + website/migrations/0065_auto_20200826_1809.py | 23 + website/migrations/0066_auto_20200827_1733.py | 28 + website/migrations/0067_auto_20200827_1738.py | 40 + website/migrations/0068_winner_hunt.py | 19 + website/models.py | 112 +- website/static/js/scripts.js | 45 +- website/static/js/velocity.min.js | 4 + .../templates/admin_dashboard_company.html | 23 +- .../admin_dashboard_company_detail.html | 8 + website/templates/base.html | 59 +- website/templates/base_dashboard_company.html | 4 +- website/templates/base_dashboard_user.html | 3 + website/templates/base_home.html | 15 +- .../company_dashboard_hunt_edit.html | 14 +- website/templates/company_hunt_results.html | 250 ++++ website/templates/create_hunt.html | 23 + website/templates/dashboard_profile.html | 1178 +++++++++++++++-- website/templates/hunt_previous.html | 127 +- website/templates/hunt_results.html | 128 ++ website/templates/hunt_submittion.html | 242 ++++ website/templates/index_user.html | 195 ++- website/templates/join.html | 839 ++++++++++++ website/templates/view_hunt.html | 143 ++ website/views.py | 622 +++++++-- 33 files changed, 4037 insertions(+), 302 deletions(-) create mode 100644 website/migrations/0059_transaction_wallet.py create mode 100644 website/migrations/0060_wallet_account_id.py create mode 100644 website/migrations/0061_payment.py create mode 100644 website/migrations/0062_company_is_active.py create mode 100644 website/migrations/0063_auto_20200826_0351.py create mode 100644 website/migrations/0064_issue_hunt.py create mode 100644 website/migrations/0065_auto_20200826_1809.py create mode 100644 website/migrations/0066_auto_20200827_1733.py create mode 100644 website/migrations/0067_auto_20200827_1738.py create mode 100644 website/migrations/0068_winner_hunt.py create mode 100644 website/static/js/velocity.min.js create mode 100644 website/templates/company_hunt_results.html create mode 100644 website/templates/hunt_results.html create mode 100644 website/templates/hunt_submittion.html create mode 100644 website/templates/join.html create mode 100644 website/templates/view_hunt.html diff --git a/bugheist/settings.py b/bugheist/settings.py index ca9bed9a3..04af78f62 100644 --- a/bugheist/settings.py +++ b/bugheist/settings.py @@ -363,4 +363,10 @@ 'toolbar': ["undo", "redo", "|","bold", "del", "italic", "quote", "ucwords", "uppercase", "lowercase", "|","h1", "h2", "h3", "h5", "h6", "|","list-ul", "list-ol", "hr", "|", "link", "reference-link", "code", "code-block", "table", "datetime", "||", "preview", "fullscreen"], 'watch' : False } -} \ No newline at end of file +} + +STRIPE_LIVE_PUBLIC_KEY = os.environ.get("STRIPE_LIVE_PUBLIC_KEY", "") +STRIPE_LIVE_SECRET_KEY = os.environ.get("STRIPE_LIVE_SECRET_KEY", "") +STRIPE_TEST_PUBLIC_KEY = os.environ.get("STRIPE_TEST_PUBLIC_KEY", "pk_test_51HFiXMFf0OkkOVnDkNs4opFLqM0Sx5GA6Pedf63uGzG1gHhumFYHEOLfCA7yzZwXUpjaa5j9ZhS1yciNhouYCMh400pSx5ZEx6") +STRIPE_TEST_SECRET_KEY = os.environ.get("STRIPE_TEST_SECRET_KEY", "sk_test_51HFiXMFf0OkkOVnDiAnuYiq6JInx3VSXw2HzIV6ihGWzaO8un5djIi990OCLTAv5PRnY7Yl8v8yuxf6yU47gvKYj00hkKaKaQ0") +STRIPE_LIVE_MODE = False # Change to True in production diff --git a/bugheist/urls.py b/bugheist/urls.py index 972e50b59..d8062d026 100644 --- a/bugheist/urls.py +++ b/bugheist/urls.py @@ -16,7 +16,7 @@ HuntCreate, DomainDetailView, StatsDetailView, InviteCreate, CreateInviteFriend, ScoreboardView,get_score,CustomObtainAuthToken,create_tokens,issue_count,get_scoreboard, CreateHunt, DraftHunts, UpcomingHunts, CompanySettings, OngoingHunts, PreviousHunts, - DomainList, UserProfileDetailsView ) + DomainList, UserProfileDetailsView, JoinCompany ) from rest_framework.authtoken import views favicon_view = RedirectView.as_view(url='/static/favicon.ico', permanent=True) @@ -26,21 +26,29 @@ urlpatterns = [ url(r'^$', website.views.index, name='index'), url(r'^dashboard/company/$', website.views.company_dashboard, name='company_dashboar_home'), + url(r'^dashboard/user/profile/addbalance$', website.views.addbalance, name='addbalance'), + url(r'^dashboard/user/profile/withdraw$', website.views.withdraw, name='withdraw'), + url(r'^dashboard/user/stripe/connected/(?P[^/]+)/$', website.views.stripe_connected, name='stripe_connected'), url(r'^dashboard/admin$', website.views.admin_dashboard, name='admin_dashboard'), url(r'^dashboard/admin/company$', website.views.admin_company_dashboard, name='admin_company_dashboard'), url(r'^dashboard/admin/company/addorupdate$', website.views.add_or_update_company, name='add_or_update_company'), url(r'^dashboard/company/domain/addorupdate$', website.views.add_or_update_domain, name='add_or_update_domain'), path('dashboard/company/domain//', website.views.company_dashboard_domain_detail, name='company_dashboard_domain_detail'), path('dashboard/company/hunt//', website.views.company_dashboard_hunt_detail, name='company_dashboard_hunt_detail'), + path('dashboard/user/hunt//', website.views.view_hunt, name='view_hunt'), + path('dashboard/user/hunt//submittion/', website.views.submit_bug, name='submit_bug'), + path('dashboard/user/hunt//results/', website.views.hunt_results, name='hunt_results'), path('dashboard/company/hunt//edit', website.views.company_dashboard_hunt_edit, name='company_dashboard_hunt_edit'), path('dashboard/admin/company//', website.views.admin_company_dashboard_detail, name='admin_company_dashboard_detail'), url(r'^dashboard/company/hunt/create$', CreateHunt.as_view(), name='create_hunt'), url(r'^dashboard/company/hunt/drafts$', DraftHunts.as_view(), name='draft_hunts'), url(r'^dashboard/company/hunt/upcoming$', UpcomingHunts.as_view(), name='upcoming_hunts'), url(r'^dashboard/company/hunt/previous$', PreviousHunts.as_view(), name='previous_hunts'), + path('dashboard/company/hunt/previous//', website.views.company_hunt_results, name='company_hunt_results'), url(r'^dashboard/company/hunt/ongoing$', OngoingHunts.as_view(), name='ongoing_hunts'), url(r'^dashboard/company/domains$', DomainList.as_view(), name='domain_list'), url(r'^dashboard/company/settings$', CompanySettings.as_view(), name='company-settings'), + url(r'^join$', JoinCompany.as_view(), name='join'), url(r'^dashboard/company/settings/role/update$', website.views.update_role, name='update-role'), url(r'^dashboard/company/settings/role/add$', website.views.add_role, name='add-role'), url(r'^dashboard/user/$', website.views.user_dashboard, name='user'), @@ -100,7 +108,7 @@ url(r'^api/v1/', include(router.urls)), url(r'^api/v1/userscore/$', website.views.get_score), url(r'^authenticate/', CustomObtainAuthToken.as_view()), - url(r'^api/v1/create_tokens/$', website.views.create_tokens), + url(r'^api/v1/createwallet/$', website.views.create_wallet), url(r'^api/v1/count/$', website.views.issue_count), url(r'^api/v1/createissues/$', csrf_exempt(IssueCreate.as_view()), name="issuecreate"), url(r'^api/v1/delete_issue/(?P\w+)/$', csrf_exempt(website.views.delete_issue)), diff --git a/website/admin.py b/website/admin.py index b71505b72..d240365b0 100644 --- a/website/admin.py +++ b/website/admin.py @@ -4,7 +4,7 @@ from import_export import resources from import_export.admin import ImportExportModelAdmin -from website.models import Issue, Points, Hunt, Domain, UserProfile, Subscription, CompanyAdmin, Company +from website.models import Winner, Payment, Transaction, Wallet, Issue, Points, Hunt, Domain, UserProfile, Subscription, CompanyAdmin, Company class UserResource(resources.ModelResource): @@ -28,6 +28,33 @@ class CompanyResource(resources.ModelResource): class Meta: model = Company +class WalletResource(resources.ModelResource): + class Meta: + model = Wallet + + +class WinnerResource(resources.ModelResource): + class Meta: + model = Winner + + +class PaymentResource(resources.ModelResource): + class Meta: + model = Payment + + +class WinnerAdmin(admin.ModelAdmin): + list_display = ( + 'id', 'hunt', 'winner', 'runner', 'second_runner', 'prize_distributed') + +class WalletAdmin(admin.ModelAdmin): + list_display = ( + 'id', 'user', 'current_balance', 'created_at') + +class PaymentAdmin(admin.ModelAdmin): + list_display = ( + 'id', 'wallet', 'value', 'active') + class IssueAdmin(admin.ModelAdmin): list_display = ( @@ -87,4 +114,7 @@ class UserAdmin(ImportExportModelAdmin): admin.site.register(CompanyAdmin, CompanyUserAdmin) admin.site.register(Company, CompanyAdmins) -admin.site.register(Subscription, SubscriptionAdmin) \ No newline at end of file +admin.site.register(Subscription, SubscriptionAdmin) +admin.site.register(Wallet, WalletAdmin) +admin.site.register(Winner, WinnerAdmin) +admin.site.register(Payment, PaymentAdmin) \ No newline at end of file diff --git a/website/migrations/0059_transaction_wallet.py b/website/migrations/0059_transaction_wallet.py new file mode 100644 index 000000000..7e5a55f60 --- /dev/null +++ b/website/migrations/0059_transaction_wallet.py @@ -0,0 +1,35 @@ +# Generated by Django 3.0.8 on 2020-08-18 09:16 + +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), + ('website', '0058_userprofile_description'), + ] + + operations = [ + migrations.CreateModel( + name='Wallet', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('current_balance', models.DecimalField(decimal_places=2, default=0, max_digits=6)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='Transaction', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('value', models.DecimalField(decimal_places=2, max_digits=6)), + ('running_balance', models.DecimalField(decimal_places=2, max_digits=6)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('wallet', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='website.Wallet')), + ], + ), + ] diff --git a/website/migrations/0060_wallet_account_id.py b/website/migrations/0060_wallet_account_id.py new file mode 100644 index 000000000..34f3d6bca --- /dev/null +++ b/website/migrations/0060_wallet_account_id.py @@ -0,0 +1,18 @@ +# Generated by Django 3.0.8 on 2020-08-19 06:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('website', '0059_transaction_wallet'), + ] + + operations = [ + migrations.AddField( + model_name='wallet', + name='account_id', + field=models.TextField(blank=True, null=True), + ), + ] diff --git a/website/migrations/0061_payment.py b/website/migrations/0061_payment.py new file mode 100644 index 000000000..abec6e2c5 --- /dev/null +++ b/website/migrations/0061_payment.py @@ -0,0 +1,23 @@ +# Generated by Django 3.0.8 on 2020-08-19 08:44 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('website', '0060_wallet_account_id'), + ] + + operations = [ + migrations.CreateModel( + name='Payment', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('value', models.DecimalField(decimal_places=2, max_digits=6)), + ('active', models.BooleanField(default=True)), + ('wallet', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='website.Wallet')), + ], + ), + ] diff --git a/website/migrations/0062_company_is_active.py b/website/migrations/0062_company_is_active.py new file mode 100644 index 000000000..99a8705b6 --- /dev/null +++ b/website/migrations/0062_company_is_active.py @@ -0,0 +1,18 @@ +# Generated by Django 3.0.8 on 2020-08-22 09:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('website', '0061_payment'), + ] + + operations = [ + migrations.AddField( + model_name='company', + name='is_active', + field=models.BooleanField(default=False), + ), + ] diff --git a/website/migrations/0063_auto_20200826_0351.py b/website/migrations/0063_auto_20200826_0351.py new file mode 100644 index 000000000..ad7051d1e --- /dev/null +++ b/website/migrations/0063_auto_20200826_0351.py @@ -0,0 +1,28 @@ +# Generated by Django 3.0.8 on 2020-08-26 03:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('website', '0062_company_is_active'), + ] + + operations = [ + migrations.AddField( + model_name='hunt', + name='prize_runner', + field=models.DecimalField(decimal_places=2, default=0, max_digits=6), + ), + migrations.AddField( + model_name='hunt', + name='prize_second_runner', + field=models.DecimalField(decimal_places=2, default=0, max_digits=6), + ), + migrations.AddField( + model_name='hunt', + name='prize_winner', + field=models.DecimalField(decimal_places=2, default=0, max_digits=6), + ), + ] diff --git a/website/migrations/0064_issue_hunt.py b/website/migrations/0064_issue_hunt.py new file mode 100644 index 000000000..1e4b77c0f --- /dev/null +++ b/website/migrations/0064_issue_hunt.py @@ -0,0 +1,19 @@ +# Generated by Django 3.0.8 on 2020-08-26 16:41 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('website', '0063_auto_20200826_0351'), + ] + + operations = [ + migrations.AddField( + model_name='issue', + name='hunt', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='website.Hunt'), + ), + ] diff --git a/website/migrations/0065_auto_20200826_1809.py b/website/migrations/0065_auto_20200826_1809.py new file mode 100644 index 000000000..96d249e44 --- /dev/null +++ b/website/migrations/0065_auto_20200826_1809.py @@ -0,0 +1,23 @@ +# Generated by Django 3.0.8 on 2020-08-26 18:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('website', '0064_issue_hunt'), + ] + + operations = [ + migrations.AddField( + model_name='issue', + name='score', + field=models.IntegerField(blank=True, null=True), + ), + migrations.AddField( + model_name='issue', + name='verified', + field=models.BooleanField(default=False), + ), + ] diff --git a/website/migrations/0066_auto_20200827_1733.py b/website/migrations/0066_auto_20200827_1733.py new file mode 100644 index 000000000..e7fcf4dc1 --- /dev/null +++ b/website/migrations/0066_auto_20200827_1733.py @@ -0,0 +1,28 @@ +# Generated by Django 3.0.8 on 2020-08-27 17:33 + +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), + ('website', '0065_auto_20200826_1809'), + ] + + operations = [ + migrations.AddField( + model_name='hunt', + name='result_published', + field=models.BooleanField(default=False), + ), + migrations.CreateModel( + name='Winner', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/website/migrations/0067_auto_20200827_1738.py b/website/migrations/0067_auto_20200827_1738.py new file mode 100644 index 000000000..3b49d33b9 --- /dev/null +++ b/website/migrations/0067_auto_20200827_1738.py @@ -0,0 +1,40 @@ +# Generated by Django 3.0.8 on 2020-08-27 17:38 + +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), + ('website', '0066_auto_20200827_1733'), + ] + + operations = [ + migrations.RemoveField( + model_name='winner', + name='user', + ), + migrations.AddField( + model_name='winner', + name='prize_distributed', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='winner', + name='runner', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='runner', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='winner', + name='second_runner', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='second_runner', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='winner', + name='winner', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='winner', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/website/migrations/0068_winner_hunt.py b/website/migrations/0068_winner_hunt.py new file mode 100644 index 000000000..2c8e6eaa4 --- /dev/null +++ b/website/migrations/0068_winner_hunt.py @@ -0,0 +1,19 @@ +# Generated by Django 3.0.8 on 2020-08-28 15:35 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('website', '0067_auto_20200827_1738'), + ] + + operations = [ + migrations.AddField( + model_name='winner', + name='hunt', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='website.Hunt'), + ), + ] diff --git a/website/models.py b/website/models.py index 1e0cb83ad..48c761c1f 100644 --- a/website/models.py +++ b/website/models.py @@ -19,12 +19,13 @@ from django.dispatch import receiver from rest_framework.authtoken.models import Token from mdeditor.fields import MDTextField - +from decimal import Decimal @receiver(post_save, sender=settings.AUTH_USER_MODEL) def create_auth_token(sender, instance=None, created=False, **kwargs): if created: Token.objects.create(user=instance) + Wallet.objects.create(user=instance) class Subscription(models.Model): @@ -45,6 +46,8 @@ class Company(models.Model): created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) subscription = models.ForeignKey(Subscription, null=True, blank=True, on_delete=models.CASCADE) + is_active = models.BooleanField(default=False) + class Domain(models.Model): company = models.ForeignKey(Company, null=True, blank=True, on_delete=models.CASCADE) @@ -136,6 +139,36 @@ def validate_image(fieldfile_obj): raise ValidationError("Max file size is %sMB" % str(megabyte_limit)) +class Hunt(models.Model): + domain = models.ForeignKey(Domain, on_delete=models.CASCADE) + name = models.CharField(max_length=25) + description = MDTextField() + url = models.URLField() + prize = models.IntegerField(null=True, blank=True) + prize_winner = models.DecimalField(max_digits=6, decimal_places=2, default=0) + prize_runner = models.DecimalField(max_digits=6, decimal_places=2, default=0) + prize_second_runner = models.DecimalField(max_digits=6, decimal_places=2, default=0) + logo = models.ImageField(upload_to="logos", null=True, blank=True) + plan = models.CharField(max_length=10) + txn_id = models.CharField(max_length=50, null=True, blank=True) + color = models.CharField(max_length=10, null=True, blank=True) + created = models.DateTimeField(auto_now_add=True) + starts_on = models.DateTimeField(null=True, blank=True) + end_on = models.DateTimeField(null=True, blank=True) + is_published = models.BooleanField(default=False) + result_published = models.BooleanField(default=False) + modified = models.DateTimeField(auto_now=True) + + @property + def domain_title(self): + parsed_url = urlparse(self.url) + return parsed_url.netloc.split(".")[-2:][0].title() + + class Meta: + ordering = ['-id'] + + + class Issue(models.Model): labels = ( (0, 'General'), @@ -147,11 +180,14 @@ class Issue(models.Model): (6, 'Design') ) user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE) + hunt = models.ForeignKey(Hunt, null=True, blank=True, on_delete=models.CASCADE) domain = models.ForeignKey(Domain, null=True, blank=True, on_delete=models.CASCADE) url = models.URLField() description = models.TextField() label = models.PositiveSmallIntegerField(choices=labels, default=0) views = models.IntegerField(null=True, blank=True) + verified = models.BooleanField(default=False) + score = models.IntegerField(null=True, blank=True) status = models.CharField(max_length=10, default="open", null=True, blank=True) user_agent = models.CharField(max_length=255, default="", null=True, blank=True) ocr = models.TextField(default="", null=True, blank=True) @@ -177,6 +213,7 @@ def hostname_domain(self): @property def domain_name(self): + print(self.url) parsed_url = urlparse(self.url) domain = parsed_url.hostname temp = domain.rsplit('.') @@ -214,6 +251,12 @@ class Meta: TWITTER_MAXLENGTH = getattr(settings, 'TWITTER_MAXLENGTH', 140) +class Winner(models.Model): + hunt = models.ForeignKey(Hunt, null=True, blank=True, on_delete=models.CASCADE) + winner = models.ForeignKey(User, related_name='winner', null=True, blank=True, on_delete=models.CASCADE) + runner = models.ForeignKey(User, related_name='runner', null=True, blank=True, on_delete=models.CASCADE) + second_runner = models.ForeignKey(User, related_name='second_runner', null=True, blank=True, on_delete=models.CASCADE) + prize_distributed = models.BooleanField(default=False) def post_to_twitter(sender, instance, *args, **kwargs): if not kwargs.get('created'): @@ -259,31 +302,6 @@ def post_to_twitter(sender, instance, *args, **kwargs): signals.post_save.connect(post_to_twitter, sender=Issue) -class Hunt(models.Model): - domain = models.ForeignKey(Domain, on_delete=models.CASCADE) - name = models.CharField(max_length=25) - description = MDTextField() - url = models.URLField() - prize = models.IntegerField(null=True, blank=True) - logo = models.ImageField(upload_to="logos", null=True, blank=True) - plan = models.CharField(max_length=10) - txn_id = models.CharField(max_length=50, null=True, blank=True) - color = models.CharField(max_length=10, null=True, blank=True) - created = models.DateTimeField(auto_now_add=True) - starts_on = models.DateTimeField(null=True, blank=True) - end_on = models.DateTimeField(null=True, blank=True) - is_published = models.BooleanField(default=False) - modified = models.DateTimeField(auto_now=True) - - @property - def domain_title(self): - parsed_url = urlparse(self.url) - return parsed_url.netloc.split(".")[-2:][0].title() - - class Meta: - ordering = ['-id'] - - class Points(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) issue = models.ForeignKey(Issue, null=True, blank=True, on_delete=models.CASCADE) @@ -380,3 +398,45 @@ class CompanyAdmin(models.Model): domain = models.ForeignKey(Domain, null=True, blank=True, on_delete=models.CASCADE) is_active = models.BooleanField(default=True) + + +class Wallet(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + account_id = models.TextField(null=True, blank=True) + current_balance = models.DecimalField(max_digits=6, decimal_places=2, default=0) + created_at = models.DateTimeField(auto_now_add=True) + def deposit(self, value): + self.transaction_set.create( + value=value, + running_balance=self.current_balance + Decimal(value) + ) + self.current_balance += Decimal(value) + self.save() + + def withdraw(self, value): + if value > self.current_balance: + raise InsufficientBalance('This wallet has insufficient balance.') + + self.transaction_set.create( + value=-value, + running_balance=self.current_balance - Decimal(value) + ) + self.current_balance -= Decimal(value) + self.save() + + def transfer(self, wallet, value): + self.withdraw(value) + wallet.deposit(value) + + + +class Transaction(models.Model): + wallet = models.ForeignKey(Wallet, on_delete=models.CASCADE) + value = models.DecimalField(max_digits=6, decimal_places=2) + running_balance = models.DecimalField(max_digits=6, decimal_places=2) + created_at = models.DateTimeField(auto_now_add=True) + +class Payment(models.Model): + wallet = models.ForeignKey(Wallet, on_delete=models.CASCADE) + value = models.DecimalField(max_digits=6, decimal_places=2) + active = models.BooleanField(default=True) \ No newline at end of file diff --git a/website/static/js/scripts.js b/website/static/js/scripts.js index 184bd5619..0686c353d 100644 --- a/website/static/js/scripts.js +++ b/website/static/js/scripts.js @@ -14,7 +14,7 @@ $("#domain"+name.getAttribute("id")).val(name.getAttribute("value")); }); - $("#update-role").submit(function(e){ + $("#update-role").submit(function(e){z e.preventDefault(); var serializedData = $(this).serialize(); console.log(serializedData) @@ -58,6 +58,49 @@ }) }); + $("#withdraw").submit(function(e){ + e.preventDefault(); + document.getElementsByClassName("overlay")[0].style.display="block"; + var serializedData = $(this).serializeArray(); + $.ajax({ + type: 'POST', + url: "/dashboard/user/profile/withdraw", + data: serializedData, + success: function (response) { + console.log(response.redirect) + if(response.status=='success'){ + window.location.href = response.redirect; + + } + else{ + window.location.reload(); + } + + }, + error: function (response) { + // alert the error if any error occured + alert(response["responseJSON"]["error"]); + } + }) + }); + + $("#addbalance").submit(function(e){ + e.preventDefault(); + var serializedData = $(this).serializeArray(); + $.ajax({ + type: 'POST', + url: "/dashboard/user/profile/addbalance", + data: serializedData, + success: function (response) { + console.log("SUCCESS") + }, + error: function (response) { + // alert the error if any error occured + alert(response["responseJSON"]["error"]); + } + }) + }); + $("#create-hunt").submit(function(e){ e.preventDefault(); diff --git a/website/static/js/velocity.min.js b/website/static/js/velocity.min.js new file mode 100644 index 000000000..33676b351 --- /dev/null +++ b/website/static/js/velocity.min.js @@ -0,0 +1,4 @@ +/*! VelocityJS.org (1.2.1). (C) 2014 Julian Shapiro. MIT @license: en.wikipedia.org/wiki/MIT_License */ +/*! VelocityJS.org jQuery Shim (1.0.1). (C) 2014 The jQuery Foundation. MIT @license: en.wikipedia.org/wiki/MIT_License. */ +!function(e){function t(e){var t=e.length,r=$.type(e);return"function"===r||$.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===r||0===t||"number"==typeof t&&t>0&&t-1 in e}if(!e.jQuery){var $=function(e,t){return new $.fn.init(e,t)};$.isWindow=function(e){return null!=e&&e==e.window},$.type=function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?a[o.call(e)]||"object":typeof e},$.isArray=Array.isArray||function(e){return"array"===$.type(e)},$.isPlainObject=function(e){var t;if(!e||"object"!==$.type(e)||e.nodeType||$.isWindow(e))return!1;try{if(e.constructor&&!n.call(e,"constructor")&&!n.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(r){return!1}for(t in e);return void 0===t||n.call(e,t)},$.each=function(e,r,a){var n,o=0,i=e.length,s=t(e);if(a){if(s)for(;i>o&&(n=r.apply(e[o],a),n!==!1);o++);else for(o in e)if(n=r.apply(e[o],a),n===!1)break}else if(s)for(;i>o&&(n=r.call(e[o],o,e[o]),n!==!1);o++);else for(o in e)if(n=r.call(e[o],o,e[o]),n===!1)break;return e},$.data=function(e,t,a){if(void 0===a){var n=e[$.expando],o=n&&r[n];if(void 0===t)return o;if(o&&t in o)return o[t]}else if(void 0!==t){var n=e[$.expando]||(e[$.expando]=++$.uuid);return r[n]=r[n]||{},r[n][t]=a,a}},$.removeData=function(e,t){var a=e[$.expando],n=a&&r[a];n&&$.each(t,function(e,t){delete n[t]})},$.extend=function(){var e,t,r,a,n,o,i=arguments[0]||{},s=1,l=arguments.length,u=!1;for("boolean"==typeof i&&(u=i,i=arguments[s]||{},s++),"object"!=typeof i&&"function"!==$.type(i)&&(i={}),s===l&&(i=this,s--);l>s;s++)if(null!=(n=arguments[s]))for(a in n)e=i[a],r=n[a],i!==r&&(u&&r&&($.isPlainObject(r)||(t=$.isArray(r)))?(t?(t=!1,o=e&&$.isArray(e)?e:[]):o=e&&$.isPlainObject(e)?e:{},i[a]=$.extend(u,o,r)):void 0!==r&&(i[a]=r));return i},$.queue=function(e,r,a){function n(e,r){var a=r||[];return null!=e&&(t(Object(e))?!function(e,t){for(var r=+t.length,a=0,n=e.length;r>a;)e[n++]=t[a++];if(r!==r)for(;void 0!==t[a];)e[n++]=t[a++];return e.length=n,e}(a,"string"==typeof e?[e]:e):[].push.call(a,e)),a}if(e){r=(r||"fx")+"queue";var o=$.data(e,r);return a?(!o||$.isArray(a)?o=$.data(e,r,n(a)):o.push(a),o):o||[]}},$.dequeue=function(e,t){$.each(e.nodeType?[e]:e,function(e,r){t=t||"fx";var a=$.queue(r,t),n=a.shift();"inprogress"===n&&(n=a.shift()),n&&("fx"===t&&a.unshift("inprogress"),n.call(r,function(){$.dequeue(r,t)}))})},$.fn=$.prototype={init:function(e){if(e.nodeType)return this[0]=e,this;throw new Error("Not a DOM node.")},offset:function(){var t=this[0].getBoundingClientRect?this[0].getBoundingClientRect():{top:0,left:0};return{top:t.top+(e.pageYOffset||document.scrollTop||0)-(document.clientTop||0),left:t.left+(e.pageXOffset||document.scrollLeft||0)-(document.clientLeft||0)}},position:function(){function e(){for(var e=this.offsetParent||document;e&&"html"===!e.nodeType.toLowerCase&&"static"===e.style.position;)e=e.offsetParent;return e||document}var t=this[0],e=e.apply(t),r=this.offset(),a=/^(?:body|html)$/i.test(e.nodeName)?{top:0,left:0}:$(e).offset();return r.top-=parseFloat(t.style.marginTop)||0,r.left-=parseFloat(t.style.marginLeft)||0,e.style&&(a.top+=parseFloat(e.style.borderTopWidth)||0,a.left+=parseFloat(e.style.borderLeftWidth)||0),{top:r.top-a.top,left:r.left-a.left}}};var r={};$.expando="velocity"+(new Date).getTime(),$.uuid=0;for(var a={},n=a.hasOwnProperty,o=a.toString,i="Boolean Number String Function Array Date RegExp Object Error".split(" "),s=0;sn;++n){var o=u(r,e,a);if(0===o)return r;var i=l(r,e,a)-t;r-=i/o}return r}function p(){for(var t=0;b>t;++t)w[t]=l(t*x,e,a)}function f(t,r,n){var o,i,s=0;do i=r+(n-r)/2,o=l(i,e,a)-t,o>0?n=i:r=i;while(Math.abs(o)>h&&++s=y?c(t,s):0==l?s:f(t,r,r+x)}function g(){V=!0,(e!=r||a!=n)&&p()}var m=4,y=.001,h=1e-7,v=10,b=11,x=1/(b-1),S="Float32Array"in t;if(4!==arguments.length)return!1;for(var P=0;4>P;++P)if("number"!=typeof arguments[P]||isNaN(arguments[P])||!isFinite(arguments[P]))return!1;e=Math.min(e,1),a=Math.min(a,1),e=Math.max(e,0),a=Math.max(a,0);var w=S?new Float32Array(b):new Array(b),V=!1,C=function(t){return V||g(),e===r&&a===n?t:0===t?0:1===t?1:l(d(t),r,n)};C.getControlPoints=function(){return[{x:e,y:r},{x:a,y:n}]};var T="generateBezier("+[e,r,a,n]+")";return C.toString=function(){return T},C}function u(e,t){var r=e;return g.isString(e)?v.Easings[e]||(r=!1):r=g.isArray(e)&&1===e.length?s.apply(null,e):g.isArray(e)&&2===e.length?b.apply(null,e.concat([t])):g.isArray(e)&&4===e.length?l.apply(null,e):!1,r===!1&&(r=v.Easings[v.defaults.easing]?v.defaults.easing:h),r}function c(e){if(e){var t=(new Date).getTime(),r=v.State.calls.length;r>1e4&&(v.State.calls=n(v.State.calls));for(var o=0;r>o;o++)if(v.State.calls[o]){var s=v.State.calls[o],l=s[0],u=s[2],f=s[3],d=!!f,m=null;f||(f=v.State.calls[o][3]=t-16);for(var y=Math.min((t-f)/u.duration,1),h=0,b=l.length;b>h;h++){var S=l[h],w=S.element;if(i(w)){var V=!1;if(u.display!==a&&null!==u.display&&"none"!==u.display){if("flex"===u.display){var C=["-webkit-box","-moz-box","-ms-flexbox","-webkit-flex"];$.each(C,function(e,t){x.setPropertyValue(w,"display",t)})}x.setPropertyValue(w,"display",u.display)}u.visibility!==a&&"hidden"!==u.visibility&&x.setPropertyValue(w,"visibility",u.visibility);for(var T in S)if("element"!==T){var k=S[T],A,F=g.isString(k.easing)?v.Easings[k.easing]:k.easing;if(1===y)A=k.endValue;else{var E=k.endValue-k.startValue;if(A=k.startValue+E*F(y,u,E),!d&&A===k.currentValue)continue}if(k.currentValue=A,"tween"===T)m=A;else{if(x.Hooks.registered[T]){var j=x.Hooks.getRoot(T),H=i(w).rootPropertyValueCache[j];H&&(k.rootPropertyValue=H)}var N=x.setPropertyValue(w,T,k.currentValue+(0===parseFloat(A)?"":k.unitType),k.rootPropertyValue,k.scrollData);x.Hooks.registered[T]&&(i(w).rootPropertyValueCache[j]=x.Normalizations.registered[j]?x.Normalizations.registered[j]("extract",null,N[1]):N[1]),"transform"===N[0]&&(V=!0)}}u.mobileHA&&i(w).transformCache.translate3d===a&&(i(w).transformCache.translate3d="(0px, 0px, 0px)",V=!0),V&&x.flushTransformCache(w)}}u.display!==a&&"none"!==u.display&&(v.State.calls[o][2].display=!1),u.visibility!==a&&"hidden"!==u.visibility&&(v.State.calls[o][2].visibility=!1),u.progress&&u.progress.call(s[1],s[1],y,Math.max(0,f+u.duration-t),f,m),1===y&&p(o)}}v.State.isTicking&&P(c)}function p(e,t){if(!v.State.calls[e])return!1;for(var r=v.State.calls[e][0],n=v.State.calls[e][1],o=v.State.calls[e][2],s=v.State.calls[e][4],l=!1,u=0,c=r.length;c>u;u++){var p=r[u].element;if(t||o.loop||("none"===o.display&&x.setPropertyValue(p,"display",o.display),"hidden"===o.visibility&&x.setPropertyValue(p,"visibility",o.visibility)),o.loop!==!0&&($.queue(p)[1]===a||!/\.velocityQueueEntryFlag/i.test($.queue(p)[1]))&&i(p)){i(p).isAnimating=!1,i(p).rootPropertyValueCache={};var f=!1;$.each(x.Lists.transforms3D,function(e,t){var r=/^scale/.test(t)?1:0,n=i(p).transformCache[t];i(p).transformCache[t]!==a&&new RegExp("^\\("+r+"[^.]").test(n)&&(f=!0,delete i(p).transformCache[t])}),o.mobileHA&&(f=!0,delete i(p).transformCache.translate3d),f&&x.flushTransformCache(p),x.Values.removeClass(p,"velocity-animating")}if(!t&&o.complete&&!o.loop&&u===c-1)try{o.complete.call(n,n)}catch(d){setTimeout(function(){throw d},1)}s&&o.loop!==!0&&s(n),o.loop!==!0||t||($.each(i(p).tweensContainer,function(e,t){/^rotate/.test(e)&&360===parseFloat(t.endValue)&&(t.endValue=0,t.startValue=360),/^backgroundPosition/.test(e)&&100===parseFloat(t.endValue)&&"%"===t.unitType&&(t.endValue=0,t.startValue=100)}),v(p,"reverse",{loop:!0,delay:o.delay})),o.queue!==!1&&$.dequeue(p,o.queue)}v.State.calls[e]=!1;for(var g=0,m=v.State.calls.length;m>g;g++)if(v.State.calls[g]!==!1){l=!0;break}l===!1&&(v.State.isTicking=!1,delete v.State.calls,v.State.calls=[])}var f=function(){if(r.documentMode)return r.documentMode;for(var e=7;e>4;e--){var t=r.createElement("div");if(t.innerHTML="",t.getElementsByTagName("span").length)return t=null,e}return a}(),d=function(){var e=0;return t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||function(t){var r=(new Date).getTime(),a;return a=Math.max(0,16-(r-e)),e=r+a,setTimeout(function(){t(r+a)},a)}}(),g={isString:function(e){return"string"==typeof e},isArray:Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)},isFunction:function(e){return"[object Function]"===Object.prototype.toString.call(e)},isNode:function(e){return e&&e.nodeType},isNodeList:function(e){return"object"==typeof e&&/^\[object (HTMLCollection|NodeList|Object)\]$/.test(Object.prototype.toString.call(e))&&e.length!==a&&(0===e.length||"object"==typeof e[0]&&e[0].nodeType>0)},isWrapped:function(e){return e&&(e.jquery||t.Zepto&&t.Zepto.zepto.isZ(e))},isSVG:function(e){return t.SVGElement&&e instanceof t.SVGElement},isEmptyObject:function(e){for(var t in e)return!1;return!0}},$,m=!1;if(e.fn&&e.fn.jquery?($=e,m=!0):$=t.Velocity.Utilities,8>=f&&!m)throw new Error("Velocity: IE8 and below require jQuery to be loaded before Velocity.");if(7>=f)return void(jQuery.fn.velocity=jQuery.fn.animate);var y=400,h="swing",v={State:{isMobile:/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),isAndroid:/Android/i.test(navigator.userAgent),isGingerbread:/Android 2\.3\.[3-7]/i.test(navigator.userAgent),isChrome:t.chrome,isFirefox:/Firefox/i.test(navigator.userAgent),prefixElement:r.createElement("div"),prefixMatches:{},scrollAnchor:null,scrollPropertyLeft:null,scrollPropertyTop:null,isTicking:!1,calls:[]},CSS:{},Utilities:$,Redirects:{},Easings:{},Promise:t.Promise,defaults:{queue:"",duration:y,easing:h,begin:a,complete:a,progress:a,display:a,visibility:a,loop:!1,delay:!1,mobileHA:!0,_cacheValues:!0},init:function(e){$.data(e,"velocity",{isSVG:g.isSVG(e),isAnimating:!1,computedStyle:null,tweensContainer:null,rootPropertyValueCache:{},transformCache:{}})},hook:null,mock:!1,version:{major:1,minor:2,patch:1},debug:!1};t.pageYOffset!==a?(v.State.scrollAnchor=t,v.State.scrollPropertyLeft="pageXOffset",v.State.scrollPropertyTop="pageYOffset"):(v.State.scrollAnchor=r.documentElement||r.body.parentNode||r.body,v.State.scrollPropertyLeft="scrollLeft",v.State.scrollPropertyTop="scrollTop");var b=function(){function e(e){return-e.tension*e.x-e.friction*e.v}function t(t,r,a){var n={x:t.x+a.dx*r,v:t.v+a.dv*r,tension:t.tension,friction:t.friction};return{dx:n.v,dv:e(n)}}function r(r,a){var n={dx:r.v,dv:e(r)},o=t(r,.5*a,n),i=t(r,.5*a,o),s=t(r,a,i),l=1/6*(n.dx+2*(o.dx+i.dx)+s.dx),u=1/6*(n.dv+2*(o.dv+i.dv)+s.dv);return r.x=r.x+l*a,r.v=r.v+u*a,r}return function a(e,t,n){var o={x:-1,v:0,tension:null,friction:null},i=[0],s=0,l=1e-4,u=.016,c,p,f;for(e=parseFloat(e)||500,t=parseFloat(t)||20,n=n||null,o.tension=e,o.friction=t,c=null!==n,c?(s=a(e,t),p=s/n*u):p=u;;)if(f=r(f||o,p),i.push(1+f.x),s+=16,!(Math.abs(f.x)>l&&Math.abs(f.v)>l))break;return c?function(e){return i[e*(i.length-1)|0]}:s}}();v.Easings={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},spring:function(e){return 1-Math.cos(4.5*e*Math.PI)*Math.exp(6*-e)}},$.each([["ease",[.25,.1,.25,1]],["ease-in",[.42,0,1,1]],["ease-out",[0,0,.58,1]],["ease-in-out",[.42,0,.58,1]],["easeInSine",[.47,0,.745,.715]],["easeOutSine",[.39,.575,.565,1]],["easeInOutSine",[.445,.05,.55,.95]],["easeInQuad",[.55,.085,.68,.53]],["easeOutQuad",[.25,.46,.45,.94]],["easeInOutQuad",[.455,.03,.515,.955]],["easeInCubic",[.55,.055,.675,.19]],["easeOutCubic",[.215,.61,.355,1]],["easeInOutCubic",[.645,.045,.355,1]],["easeInQuart",[.895,.03,.685,.22]],["easeOutQuart",[.165,.84,.44,1]],["easeInOutQuart",[.77,0,.175,1]],["easeInQuint",[.755,.05,.855,.06]],["easeOutQuint",[.23,1,.32,1]],["easeInOutQuint",[.86,0,.07,1]],["easeInExpo",[.95,.05,.795,.035]],["easeOutExpo",[.19,1,.22,1]],["easeInOutExpo",[1,0,0,1]],["easeInCirc",[.6,.04,.98,.335]],["easeOutCirc",[.075,.82,.165,1]],["easeInOutCirc",[.785,.135,.15,.86]]],function(e,t){v.Easings[t[0]]=l.apply(null,t[1])});var x=v.CSS={RegEx:{isHex:/^#([A-f\d]{3}){1,2}$/i,valueUnwrap:/^[A-z]+\((.*)\)$/i,wrappedValueAlreadyExtracted:/[0-9.]+ [0-9.]+ [0-9.]+( [0-9.]+)?/,valueSplit:/([A-z]+\(.+\))|(([A-z0-9#-.]+?)(?=\s|$))/gi},Lists:{colors:["fill","stroke","stopColor","color","backgroundColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor","outlineColor"],transformsBase:["translateX","translateY","scale","scaleX","scaleY","skewX","skewY","rotateZ"],transforms3D:["transformPerspective","translateZ","scaleZ","rotateX","rotateY"]},Hooks:{templates:{textShadow:["Color X Y Blur","black 0px 0px 0px"],boxShadow:["Color X Y Blur Spread","black 0px 0px 0px 0px"],clip:["Top Right Bottom Left","0px 0px 0px 0px"],backgroundPosition:["X Y","0% 0%"],transformOrigin:["X Y Z","50% 50% 0px"],perspectiveOrigin:["X Y","50% 50%"]},registered:{},register:function(){for(var e=0;e=f)switch(e){case"name":return"filter";case"extract":var a=r.toString().match(/alpha\(opacity=(.*)\)/i);return r=a?a[1]/100:1;case"inject":return t.style.zoom=1,parseFloat(r)>=1?"":"alpha(opacity="+parseInt(100*parseFloat(r),10)+")"}else switch(e){case"name":return"opacity";case"extract":return r;case"inject":return r}}},register:function(){9>=f||v.State.isGingerbread||(x.Lists.transformsBase=x.Lists.transformsBase.concat(x.Lists.transforms3D));for(var e=0;en&&(n=1),o=!/(\d)$/i.test(n);break;case"skew":o=!/(deg|\d)$/i.test(n);break;case"rotate":o=!/(deg|\d)$/i.test(n)}return o||(i(r).transformCache[t]="("+n+")"),i(r).transformCache[t]}}}();for(var e=0;e=f||3!==o.split(" ").length||(o+=" 1"),o;case"inject":return 8>=f?4===n.split(" ").length&&(n=n.split(/\s+/).slice(0,3).join(" ")):3===n.split(" ").length&&(n+=" 1"),(8>=f?"rgb":"rgba")+"("+n.replace(/\s+/g,",").replace(/\.(\d)+(?=,)/g,"")+")"}}}()}},Names:{camelCase:function(e){return e.replace(/-(\w)/g,function(e,t){return t.toUpperCase()})},SVGAttribute:function(e){var t="width|height|x|y|cx|cy|r|rx|ry|x1|x2|y1|y2";return(f||v.State.isAndroid&&!v.State.isChrome)&&(t+="|transform"),new RegExp("^("+t+")$","i").test(e)},prefixCheck:function(e){if(v.State.prefixMatches[e])return[v.State.prefixMatches[e],!0];for(var t=["","Webkit","Moz","ms","O"],r=0,a=t.length;a>r;r++){var n;if(n=0===r?e:t[r]+e.replace(/^\w/,function(e){return e.toUpperCase()}),g.isString(v.State.prefixElement.style[n]))return v.State.prefixMatches[e]=n,[n,!0]}return[e,!1]}},Values:{hexToRgb:function(e){var t=/^#?([a-f\d])([a-f\d])([a-f\d])$/i,r=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,a;return e=e.replace(t,function(e,t,r,a){return t+t+r+r+a+a}),a=r.exec(e),a?[parseInt(a[1],16),parseInt(a[2],16),parseInt(a[3],16)]:[0,0,0]},isCSSNullValue:function(e){return 0==e||/^(none|auto|transparent|(rgba\(0, ?0, ?0, ?0\)))$/i.test(e)},getUnitType:function(e){return/^(rotate|skew)/i.test(e)?"deg":/(^(scale|scaleX|scaleY|scaleZ|alpha|flexGrow|flexHeight|zIndex|fontWeight)$)|((opacity|red|green|blue|alpha)$)/i.test(e)?"":"px"},getDisplayType:function(e){var t=e&&e.tagName.toString().toLowerCase();return/^(b|big|i|small|tt|abbr|acronym|cite|code|dfn|em|kbd|strong|samp|var|a|bdo|br|img|map|object|q|script|span|sub|sup|button|input|label|select|textarea)$/i.test(t)?"inline":/^(li)$/i.test(t)?"list-item":/^(tr)$/i.test(t)?"table-row":/^(table)$/i.test(t)?"table":/^(tbody)$/i.test(t)?"table-row-group":"block"},addClass:function(e,t){e.classList?e.classList.add(t):e.className+=(e.className.length?" ":"")+t},removeClass:function(e,t){e.classList?e.classList.remove(t):e.className=e.className.toString().replace(new RegExp("(^|\\s)"+t.split(" ").join("|")+"(\\s|$)","gi")," ")}},getPropertyValue:function(e,r,n,o){function s(e,r){function n(){u&&x.setPropertyValue(e,"display","none")}var l=0;if(8>=f)l=$.css(e,r);else{var u=!1;if(/^(width|height)$/.test(r)&&0===x.getPropertyValue(e,"display")&&(u=!0,x.setPropertyValue(e,"display",x.Values.getDisplayType(e))),!o){if("height"===r&&"border-box"!==x.getPropertyValue(e,"boxSizing").toString().toLowerCase()){var c=e.offsetHeight-(parseFloat(x.getPropertyValue(e,"borderTopWidth"))||0)-(parseFloat(x.getPropertyValue(e,"borderBottomWidth"))||0)-(parseFloat(x.getPropertyValue(e,"paddingTop"))||0)-(parseFloat(x.getPropertyValue(e,"paddingBottom"))||0);return n(),c}if("width"===r&&"border-box"!==x.getPropertyValue(e,"boxSizing").toString().toLowerCase()){var p=e.offsetWidth-(parseFloat(x.getPropertyValue(e,"borderLeftWidth"))||0)-(parseFloat(x.getPropertyValue(e,"borderRightWidth"))||0)-(parseFloat(x.getPropertyValue(e,"paddingLeft"))||0)-(parseFloat(x.getPropertyValue(e,"paddingRight"))||0);return n(),p}}var d;d=i(e)===a?t.getComputedStyle(e,null):i(e).computedStyle?i(e).computedStyle:i(e).computedStyle=t.getComputedStyle(e,null),"borderColor"===r&&(r="borderTopColor"),l=9===f&&"filter"===r?d.getPropertyValue(r):d[r],(""===l||null===l)&&(l=e.style[r]),n()}if("auto"===l&&/^(top|right|bottom|left)$/i.test(r)){var g=s(e,"position");("fixed"===g||"absolute"===g&&/top|left/i.test(r))&&(l=$(e).position()[r]+"px")}return l}var l;if(x.Hooks.registered[r]){var u=r,c=x.Hooks.getRoot(u);n===a&&(n=x.getPropertyValue(e,x.Names.prefixCheck(c)[0])),x.Normalizations.registered[c]&&(n=x.Normalizations.registered[c]("extract",e,n)),l=x.Hooks.extractValue(u,n)}else if(x.Normalizations.registered[r]){var p,d;p=x.Normalizations.registered[r]("name",e),"transform"!==p&&(d=s(e,x.Names.prefixCheck(p)[0]),x.Values.isCSSNullValue(d)&&x.Hooks.templates[r]&&(d=x.Hooks.templates[r][1])),l=x.Normalizations.registered[r]("extract",e,d)}if(!/^[\d-]/.test(l))if(i(e)&&i(e).isSVG&&x.Names.SVGAttribute(r))if(/^(height|width)$/i.test(r))try{l=e.getBBox()[r]}catch(g){l=0}else l=e.getAttribute(r);else l=s(e,x.Names.prefixCheck(r)[0]);return x.Values.isCSSNullValue(l)&&(l=0),v.debug>=2&&console.log("Get "+r+": "+l),l},setPropertyValue:function(e,r,a,n,o){var s=r;if("scroll"===r)o.container?o.container["scroll"+o.direction]=a:"Left"===o.direction?t.scrollTo(a,o.alternateValue):t.scrollTo(o.alternateValue,a);else if(x.Normalizations.registered[r]&&"transform"===x.Normalizations.registered[r]("name",e))x.Normalizations.registered[r]("inject",e,a),s="transform",a=i(e).transformCache[r];else{if(x.Hooks.registered[r]){var l=r,u=x.Hooks.getRoot(r);n=n||x.getPropertyValue(e,u),a=x.Hooks.injectValue(l,a,n),r=u}if(x.Normalizations.registered[r]&&(a=x.Normalizations.registered[r]("inject",e,a),r=x.Normalizations.registered[r]("name",e)),s=x.Names.prefixCheck(r)[0],8>=f)try{e.style[s]=a}catch(c){v.debug&&console.log("Browser does not support ["+a+"] for ["+s+"]")}else i(e)&&i(e).isSVG&&x.Names.SVGAttribute(r)?e.setAttribute(r,a):e.style[s]=a;v.debug>=2&&console.log("Set "+r+" ("+s+"): "+a)}return[s,a]},flushTransformCache:function(e){function t(t){return parseFloat(x.getPropertyValue(e,t))}var r="";if((f||v.State.isAndroid&&!v.State.isChrome)&&i(e).isSVG){var a={translate:[t("translateX"),t("translateY")],skewX:[t("skewX")],skewY:[t("skewY")],scale:1!==t("scale")?[t("scale"),t("scale")]:[t("scaleX"),t("scaleY")],rotate:[t("rotateZ"),0,0]};$.each(i(e).transformCache,function(e){/^translate/i.test(e)?e="translate":/^scale/i.test(e)?e="scale":/^rotate/i.test(e)&&(e="rotate"),a[e]&&(r+=e+"("+a[e].join(" ")+") ",delete a[e])})}else{var n,o;$.each(i(e).transformCache,function(t){return n=i(e).transformCache[t],"transformPerspective"===t?(o=n,!0):(9===f&&"rotateZ"===t&&(t="rotate"),void(r+=t+n+" "))}),o&&(r="perspective"+o+" "+r)}x.setPropertyValue(e,"transform",r)}};x.Hooks.register(),x.Normalizations.register(),v.hook=function(e,t,r){var n=a;return e=o(e),$.each(e,function(e,o){if(i(o)===a&&v.init(o),r===a)n===a&&(n=v.CSS.getPropertyValue(o,t));else{var s=v.CSS.setPropertyValue(o,t,r);"transform"===s[0]&&v.CSS.flushTransformCache(o),n=s}}),n};var S=function(){function e(){return l?T.promise||null:f}function n(){function e(e){function p(e,t){var r=a,i=a,s=a;return g.isArray(e)?(r=e[0],!g.isArray(e[1])&&/^[\d-]/.test(e[1])||g.isFunction(e[1])||x.RegEx.isHex.test(e[1])?s=e[1]:(g.isString(e[1])&&!x.RegEx.isHex.test(e[1])||g.isArray(e[1]))&&(i=t?e[1]:u(e[1],o.duration),e[2]!==a&&(s=e[2]))):r=e,t||(i=i||o.easing),g.isFunction(r)&&(r=r.call(n,w,P)),g.isFunction(s)&&(s=s.call(n,w,P)),[r||0,i,s]}function f(e,t){var r,a;return a=(t||"0").toString().toLowerCase().replace(/[%A-z]+$/,function(e){return r=e,""}),r||(r=x.Values.getUnitType(e)),[a,r]}function d(){var e={myParent:n.parentNode||r.body,position:x.getPropertyValue(n,"position"),fontSize:x.getPropertyValue(n,"fontSize")},a=e.position===N.lastPosition&&e.myParent===N.lastParent,o=e.fontSize===N.lastFontSize;N.lastParent=e.myParent,N.lastPosition=e.position,N.lastFontSize=e.fontSize;var s=100,l={};if(o&&a)l.emToPx=N.lastEmToPx,l.percentToPxWidth=N.lastPercentToPxWidth,l.percentToPxHeight=N.lastPercentToPxHeight;else{var u=i(n).isSVG?r.createElementNS("http://www.w3.org/2000/svg","rect"):r.createElement("div");v.init(u),e.myParent.appendChild(u),$.each(["overflow","overflowX","overflowY"],function(e,t){v.CSS.setPropertyValue(u,t,"hidden")}),v.CSS.setPropertyValue(u,"position",e.position),v.CSS.setPropertyValue(u,"fontSize",e.fontSize),v.CSS.setPropertyValue(u,"boxSizing","content-box"),$.each(["minWidth","maxWidth","width","minHeight","maxHeight","height"],function(e,t){v.CSS.setPropertyValue(u,t,s+"%")}),v.CSS.setPropertyValue(u,"paddingLeft",s+"em"),l.percentToPxWidth=N.lastPercentToPxWidth=(parseFloat(x.getPropertyValue(u,"width",null,!0))||1)/s,l.percentToPxHeight=N.lastPercentToPxHeight=(parseFloat(x.getPropertyValue(u,"height",null,!0))||1)/s,l.emToPx=N.lastEmToPx=(parseFloat(x.getPropertyValue(u,"paddingLeft"))||1)/s,e.myParent.removeChild(u)}return null===N.remToPx&&(N.remToPx=parseFloat(x.getPropertyValue(r.body,"fontSize"))||16),null===N.vwToPx&&(N.vwToPx=parseFloat(t.innerWidth)/100,N.vhToPx=parseFloat(t.innerHeight)/100),l.remToPx=N.remToPx,l.vwToPx=N.vwToPx,l.vhToPx=N.vhToPx,v.debug>=1&&console.log("Unit ratios: "+JSON.stringify(l),n),l}if(o.begin&&0===w)try{o.begin.call(m,m)}catch(y){setTimeout(function(){throw y},1)}if("scroll"===k){var S=/^x$/i.test(o.axis)?"Left":"Top",V=parseFloat(o.offset)||0,C,A,F;o.container?g.isWrapped(o.container)||g.isNode(o.container)?(o.container=o.container[0]||o.container,C=o.container["scroll"+S],F=C+$(n).position()[S.toLowerCase()]+V):o.container=null:(C=v.State.scrollAnchor[v.State["scrollProperty"+S]],A=v.State.scrollAnchor[v.State["scrollProperty"+("Left"===S?"Top":"Left")]],F=$(n).offset()[S.toLowerCase()]+V),s={scroll:{rootPropertyValue:!1,startValue:C,currentValue:C,endValue:F,unitType:"",easing:o.easing,scrollData:{container:o.container,direction:S,alternateValue:A}},element:n},v.debug&&console.log("tweensContainer (scroll): ",s.scroll,n)}else if("reverse"===k){if(!i(n).tweensContainer)return void $.dequeue(n,o.queue);"none"===i(n).opts.display&&(i(n).opts.display="auto"),"hidden"===i(n).opts.visibility&&(i(n).opts.visibility="visible"),i(n).opts.loop=!1,i(n).opts.begin=null,i(n).opts.complete=null,b.easing||delete o.easing,b.duration||delete o.duration,o=$.extend({},i(n).opts,o);var E=$.extend(!0,{},i(n).tweensContainer);for(var j in E)if("element"!==j){var H=E[j].startValue;E[j].startValue=E[j].currentValue=E[j].endValue,E[j].endValue=H,g.isEmptyObject(b)||(E[j].easing=o.easing),v.debug&&console.log("reverse tweensContainer ("+j+"): "+JSON.stringify(E[j]),n)}s=E}else if("start"===k){var E;i(n).tweensContainer&&i(n).isAnimating===!0&&(E=i(n).tweensContainer),$.each(h,function(e,t){if(RegExp("^"+x.Lists.colors.join("$|^")+"$").test(e)){var r=p(t,!0),n=r[0],o=r[1],i=r[2];if(x.RegEx.isHex.test(n)){for(var s=["Red","Green","Blue"],l=x.Values.hexToRgb(n),u=i?x.Values.hexToRgb(i):a,c=0;cO;O++){var z={delay:F.delay,progress:F.progress};O===R-1&&(z.display=F.display,z.visibility=F.visibility,z.complete=F.complete),S(m,"reverse",z)}return e()}};v=$.extend(S,v),v.animate=S;var P=t.requestAnimationFrame||d;return v.State.isMobile||r.hidden===a||r.addEventListener("visibilitychange",function(){r.hidden?(P=function(e){return setTimeout(function(){e(!0)},16)},c()):P=t.requestAnimationFrame||d}),e.Velocity=v,e!==t&&(e.fn.velocity=S,e.fn.velocity.defaults=v.defaults),$.each(["Down","Up"],function(e,t){v.Redirects["slide"+t]=function(e,r,n,o,i,s){var l=$.extend({},r),u=l.begin,c=l.complete,p={height:"",marginTop:"",marginBottom:"",paddingTop:"",paddingBottom:""},f={};l.display===a&&(l.display="Down"===t?"inline"===v.CSS.Values.getDisplayType(e)?"inline-block":"block":"none"),l.begin=function(){u&&u.call(i,i);for(var r in p){f[r]=e.style[r];var a=v.CSS.getPropertyValue(e,r);p[r]="Down"===t?[a,0]:[0,a]}f.overflow=e.style.overflow,e.style.overflow="hidden"},l.complete=function(){for(var t in f)e.style[t]=f[t];c&&c.call(i,i),s&&s.resolver(i)},v(e,p,l)}}),$.each(["In","Out"],function(e,t){v.Redirects["fade"+t]=function(e,r,n,o,i,s){var l=$.extend({},r),u={opacity:"In"===t?1:0},c=l.complete;l.complete=n!==o-1?l.begin=null:function(){c&&c.call(i,i),s&&s.resolver(i)},l.display===a&&(l.display="In"===t?"auto":"none"),v(this,u,l)}}),v}(window.jQuery||window.Zepto||window,window,document)}); \ No newline at end of file diff --git a/website/templates/admin_dashboard_company.html b/website/templates/admin_dashboard_company.html index 6e15a8d2d..724d87768 100644 --- a/website/templates/admin_dashboard_company.html +++ b/website/templates/admin_dashboard_company.html @@ -4,22 +4,21 @@
{% if companys %} - {% for company in companys %} -
-
- -
-
{{company.name}}
-
-

{{company.email}}$

-
-
-
-
+
+ Company + {% for company in companys %} + {% if company.is_active %} + {{company.name}} + {% else %} + {{company.name}} + {% endif %} + {% endfor %} +
{% else %}
no company found ! {% endif %} +
diff --git a/website/templates/admin_dashboard_company_detail.html b/website/templates/admin_dashboard_company_detail.html index 9e14cc8c2..ad0a026bd 100644 --- a/website/templates/admin_dashboard_company_detail.html +++ b/website/templates/admin_dashboard_company_detail.html @@ -40,6 +40,14 @@ +
+ + {% else %} + Verify + {% endif %} +
-
+ --> +
{% block content %} {% endblock %}
diff --git a/website/templates/base_dashboard_user.html b/website/templates/base_dashboard_user.html index f9d59cacc..3913a0a7f 100644 --- a/website/templates/base_dashboard_user.html +++ b/website/templates/base_dashboard_user.html @@ -101,6 +101,9 @@

Dashboard

{% endif %} {{ request.user.username }} +
  • Balance - {{wallet.current_balance}}$ +
  • +
    diff --git a/website/templates/company_dashboard_hunt_edit.html b/website/templates/company_dashboard_hunt_edit.html index 0859b4cbd..aceef695e 100644 --- a/website/templates/company_dashboard_hunt_edit.html +++ b/website/templates/company_dashboard_hunt_edit.html @@ -54,7 +54,7 @@ -
    + {% csrf_token%}
    + Prizes +
    + + + + (Your wallet must contain the total prize money, if not you can go to profile to add money to wallet) +
    @@ -376,7 +1151,7 @@

    Recent Activity

    {% for activity in activities %} -
    {{ activity.domain_name }}
    +
    {{ activity.domain_name }}
    @@ -479,6 +1254,197 @@
    2 Years
    +{% if user == request.user %} + + +{% endif %} + + + + + + + + + + + + + + +{% endblock %} diff --git a/website/templates/hunt_submittion.html b/website/templates/hunt_submittion.html new file mode 100644 index 000000000..e74aa6459 --- /dev/null +++ b/website/templates/hunt_submittion.html @@ -0,0 +1,242 @@ +{% extends "base_dashboard_user.html" %} +{% load static %} +{% load gravatar %} +{% load socialaccount %} +{% load humanize %} +{% providers_media_js %} + +{% block style %} + .duplicates { + border-radius: 0px; + } + +table { + border: 1px solid #ccc; + border-collapse: collapse; + margin: 0; + padding: 0; + width: 100%; + table-layout: fixed; +} + +table caption { + font-size: 1.5em; + margin: .5em 0 .75em; + text-align: center; +} + +table tr { + background-color: #f8f8f8; + border: 1px solid #ddd; + padding: .35em; +} + +table th, +table td { + padding: .625em; + text-align: center; +} + +table th { + font-size: .85em; + letter-spacing: .1em; + text-transform: uppercase; +} + +@media screen and (max-width: 600px) { + table { + border: 0; + } + + table caption { + font-size: 1.3em; + } + + table thead { + border: none; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; + } + + table tr { + border-bottom: 3px solid #ddd; + display: block; + margin-bottom: .625em; + } + + table td { + border-bottom: 1px solid #ddd; + display: block; + font-size: .8em; + text-align: right; + } + + table td::before { + /* + * aria-label has no advantage, it won't be read inside a table + content: attr(aria-label); + */ + content: attr(data-label); + float: left; + font-weight: bold; + text-transform: uppercase; + } + + table td:last-child { + border-bottom: 0; + } +} +{% endblock %} + +{% block content %} + + + +
    + {% csrf_token %} +
    +
    +
    +

    Report a bug

    +
    +
    +
    +
    + +
    +
    + + {% if request.GET.url %} + + {% else %} + + {% endif %} + Check for Duplicates +
    + + {{ form.url.errors }} +
    +
    +
    + + +
    + {{ form.description.errors }} +
    +
    + + + + +
    +
    + {% if request.GET.hash %}
    + + + {% else %} +
    + + + + {{ form.screenshot.errors }} + + + {% endif %} +
    + +
    + + + {% if issue_list %} + + + + + + + + + + + {% for issue in issue_list %} + + + + + + + {% endfor %} + + {% endif %} +
    Report Summary
    idURLDescriptionType
    {{ forloop.counter }}{{issue.url}}{{issue.description}}{{issue.get_label_display}}
    + +{% endblock %} diff --git a/website/templates/index_user.html b/website/templates/index_user.html index bbc9d0d91..7eef4431f 100644 --- a/website/templates/index_user.html +++ b/website/templates/index_user.html @@ -6,55 +6,166 @@ {% providers_media_js %} {% load i18n %} {% block content %} +
    -
    -

    Ongoing Hunt

    -
    -
    - -
    -
    Description
    -
    -

    A Hunt

    -
    -
    -
    + {% if upcoming_hunts %} +
    +

    Upcoming Hunt

    +
      + {% for hunt in upcoming_hunts %} +
    • +
      + {% if hunt.logo %} +
      + {% endif %} +
      +

      {{hunt.name}}

      +

      {{hunt.domain.name}}, {{hunt.domain.company.name}} - Starts on {{hunt.starts_on}}

      + + + +
      +
      +
    • + {% endfor %} +
    +
    -
    -
    + {% endif %}
    -
    -

    Upcoming Hunt

    -
    -
    - -
    -
    Description
    -
    -

    A hunt

    -
    -
    -
    + {% if ongoing_hunt %} +
    +

    Ongoing Hunt

    +
      + {% for hunt in ongoing_hunt %} +
    • +
      + {% if hunt.logo %} +
      + {% endif %} +
      +

      {{hunt.name}}

      +

      {{hunt.domain.name}}, {{hunt.domain.company.name}} - Already Started

      + + + +
      +
      +
    • + {% endfor %} +
    +
    -
    -
    + {% endif %}
    -
    -

    Previous Hunt

    -
    -
    - -
    -
    Descrirption
    -
    -

    A Hunt

    -
    -
    -
    + {% if previous_hunt %} +
    +

    Previous Hunt

    +
      + {% for hunt in previous_hunt %} +
    • +
      + {% if hunt.logo %} +
      + {% endif %} +
      +

      {{hunt.name}}

      +

      {{hunt.domain.name}}, {{hunt.domain.company.name}} - Ended on {{hunt.end_on}}

      + + + +
      +
      +
    • + {% endfor %} +
    +
    -
    -
    + {% endif %}
    + {% endblock %} diff --git a/website/templates/join.html b/website/templates/join.html new file mode 100644 index 000000000..6a45dd22f --- /dev/null +++ b/website/templates/join.html @@ -0,0 +1,839 @@ +{% extends "base.html" %} +{% load static %} +{% load gravatar %} +{% load i18n %} +{% block style %} + @import url('https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,400;0,700;1,400;1,700&family=Roboto+Slab:wght@400;700&display=swap'); + +html { + height: 100%; + min-height:800px; +} +body { + background: url('https://i.pinimg.com/originals/48/79/86/487986c17560a8ed1afdc55e480e5be2.png'); + background-size:cover; + background-repeat:no-repeat; + text-align: center; + font-family: 'Noto Sans', sans-serif; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +h1{ + font-weight:400; + padding-top:0; + margin-top:0; + font-family: 'Roboto Slab', serif; +} + +#svg_form_time { + height: 15px; + max-width: 80%; + margin: 40px auto 20px; + display: block; +} + +#svg_form_time circle, +#svg_form_time rect { + fill: white; +} + +.button { + background: rgb(237, 40, 70); + border-radius: 5px; + padding: 15px 25px; + display: inline-block; + margin: 10px; + font-weight: bold; + color: white; + cursor: pointer; + box-shadow:0px 2px 5px rgb(0,0,0,0.5); +} + +.disabled { + display:none; +} + +section { + padding: 50px ; + max-width: 300px; + margin: 30px auto; + background:white; + background:rgba(255,255,255,0.9); + backdrop-filter:blur(10px); + box-shadow:0px 2px 10px rgba(0,0,0,0.3); + border-radius:5px; + transition:transform 0.2s ease-in-out; +} + + +input { + width: 100%; + margin: 7px 0px; + display: inline-block; + padding: 12px 25px; + box-sizing: border-box; + border-radius: 5px; + border: 1px solid lightgrey; + font-size: 1em; + font-family:inherit; + background:white; +} + +p{ + text-align:justify; +margin-top:0; +} +.subrow .col-md-6:nth-child(1) .panel { + background-color: #F76B78; + } + + .subrow .col-md-6:nth-child(2) .panel { + background-color: #DC4353; + } + + .subrow .col-md-6:nth-child(3) .panel { + background-color: #C41E2E; + } + + .subrow .col-md-6:nth-child(4) .panel { + background-color: #9B0C1A; + } + + .subrow .col-md-6:nth-child(1) .panel button { + background-color: #F76B78; + border-color: #F76B78; + } + + .subrow .col-md-6:nth-child(2) .panel button { + background-color: #DC4353; + border-color: #DC4353; + } + + .subrow .col-md-6:nth-child(3) .panel button { + background-color: #C41E2E; + border-color: #C41E2E; + } + + .subrow .col-md-6:nth-child(4) .panel button { + background-color: #9B0C1A; + border-color: #9B0C1A; + } + + .image-subs { + margin-left: 10px; + } + + .plan-style { + font-size: 24pt + } + + .plan-color { + color: white; + } + + .newsletter { + font-size: 18pt; + } + + .announce { + font-size: 20pt; + } + label { + width: 100%; + display: block; +} + +.card-input-element { + display: none; +} + +.card-input { + margin: 10px; + padding: 00px; +} + +.card-input:hover { + cursor: pointer; +} + +.card-input-element:checked + .card-input { + box-shadow: 0 0 1px 1px #dc4853; + } + .panel-heading { + background-color: #DC4353; +} +.panel-body { + border: 1px solid #a7a7b1; + border-top: none; +} + +.simplebox, .simplebutton { +outline: none; +border: 1px solid #ddd !important; +-webkit-box-shadow: none !important; +-moz-box-shadow: none !important; +box-shadow: none !important; +font-size:12px; +} + +.formHolder { + +margin:0 auto; + + +border-radius: 6px; +overflow:hidden; + + + +} + +.formHolder h3 { +margin:0 0 14px 0; +font-size:19px; +font-weight:600; +} + +.wallet { +display:none; +} + +.card .cardButton { +margin-right:5px; +} + +.wallet .cardButton { +margin-left:5px; +} + +.wallet { +display:none; +} + .overlay { + background: #ff1d1d; + display: none; + position: absolute; + top: 0; + right: 0; + z-index: 3000; + bottom: 0; + left: 0; + opacity: 0.5; +} +.center { + position: absolute; + width: 20%; + height: 20%; + top: 30%; + left: 42%; +} + +.dot-1 { + position: absolute; + z-index: 3; + width: 30px; + height: 30px; + top: 95px; + left: 95px; + background: #fff; + border-radius: 50%; + -webkit-animation-fill-mode: both; + animation-fill-mode: both; + -webkit-animation: jump-jump-1 2s cubic-bezier(0.21, 0.98, 0.6, 0.99) infinite alternate; + animation: jump-jump-1 2s cubic-bezier(0.21, 0.98, 0.6, 0.99) infinite alternate; +} + +.dot-2 { + position: absolute; + z-index: 2; + width: 60px; + height: 60px; + top: 80px; + left: 80px; + background: #fff; + border-radius: 50%; + -webkit-animation-fill-mode: both; + animation-fill-mode: both; + -webkit-animation: jump-jump-2 2s cubic-bezier(0.21, 0.98, 0.6, 0.99) infinite alternate; + animation: jump-jump-2 2s cubic-bezier(0.21, 0.98, 0.6, 0.99) infinite alternate; +} + +.dot-3 { + position: absolute; + z-index: 1; + width: 90px; + height: 90px; + top: 65px; + left: 65px; + background: #fff; + border-radius: 50%; + -webkit-animation-fill-mode: both; + animation-fill-mode: both; + -webkit-animation: jump-jump-3 2s cubic-bezier(0.21, 0.98, 0.6, 0.99) infinite alternate; + animation: jump-jump-3 2s cubic-bezier(0.21, 0.98, 0.6, 0.99) infinite alternate; +} + +@-webkit-keyframes jump-jump-1 { + 0%, 70% { + box-shadow: 2px 2px 3px 2px rgba(0, 0, 0, 0.2); + -webkit-transform: scale(0); + transform: scale(0); + } + 100% { + box-shadow: 10px 10px 15px 0 rgba(0, 0, 0, 0.3); + -webkit-transform: scale(1); + transform: scale(1); + } +} + +@keyframes jump-jump-1 { + 0%, 70% { + box-shadow: 2px 2px 3px 2px rgba(0, 0, 0, 0.2); + -webkit-transform: scale(0); + transform: scale(0); + } + 100% { + box-shadow: 10px 10px 15px 0 rgba(0, 0, 0, 0.3); + -webkit-transform: scale(1); + transform: scale(1); + } +} +@-webkit-keyframes jump-jump-2 { + 0%, 40% { + box-shadow: 2px 2px 3px 2px rgba(0, 0, 0, 0.2); + -webkit-transform: scale(0); + transform: scale(0); + } + 100% { + box-shadow: 10px 10px 15px 0 rgba(0, 0, 0, 0.3); + -webkit-transform: scale(1); + transform: scale(1); + } +} +@keyframes jump-jump-2 { + 0%, 40% { + box-shadow: 2px 2px 3px 2px rgba(0, 0, 0, 0.2); + -webkit-transform: scale(0); + transform: scale(0); + } + 100% { + box-shadow: 10px 10px 15px 0 rgba(0, 0, 0, 0.3); + -webkit-transform: scale(1); + transform: scale(1); + } +} +@-webkit-keyframes jump-jump-3 { + 0%, 10% { + box-shadow: 2px 2px 3px 2px rgba(0, 0, 0, 0.2); + -webkit-transform: scale(0); + transform: scale(0); + } + 100% { + box-shadow: 10px 10px 15px 0 rgba(0, 0, 0, 0.3); + -webkit-transform: scale(1); + transform: scale(1); + } +} +@keyframes jump-jump-3 { + 0%, 10% { + box-shadow: 2px 2px 3px 2px rgba(0, 0, 0, 0.2); + -webkit-transform: scale(0); + transform: scale(0); + } + 100% { + box-shadow: 10px 10px 15px 0 rgba(0, 0, 0, 0.3); + -webkit-transform: scale(1); + transform: scale(1); + } +} + +{% endblock %} + +{% block content %} + + +
    +
    +
    + {% csrf_token %} +

    Create Company

    +
    +

    Company information

    + + + + +
    + +
    +

    Subscription

    +
    + +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + +
    + +
    + {% ifnotequal wallet.current_balance 0 %} +
    +

    Wallet

    + Current Balance : {{wallet.current_balance}}$ + + +
    + {% endifnotequal %} +
    + +

    Card

    + + +
    + +
    + +
    + +
    + + + +
    + + +
    + + {% ifnotequal wallet.current_balance 0 %} + + {% endifnotequal %} +
    +
    + +
    +

    General condtitions

    +

    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

    +
    + + + + +
    +
    +{% endblock %} + +{% block after_js %} + + + +{% endblock %} diff --git a/website/templates/view_hunt.html b/website/templates/view_hunt.html new file mode 100644 index 000000000..b52b28941 --- /dev/null +++ b/website/templates/view_hunt.html @@ -0,0 +1,143 @@ +{% extends "base_dashboard_user.html" %} +{% load static %} +{% block content %} + + + + + +
    + + + + +
    + +
    +
    Hunt URL : {{ hunt.domain.url }}
    + + + + + + + + + + + + + +{% endblock %} diff --git a/website/views.py b/website/views.py index 413b5ae4a..e336fc56d 100644 --- a/website/views.py +++ b/website/views.py @@ -50,9 +50,12 @@ from rest_framework.response import Response from rest_framework.authtoken.views import ObtainAuthToken -from website.models import Issue, Points, Hunt, Domain, InviteFriend, UserProfile, IP, CompanyAdmin, Subscription, Company +from website.models import Winner, Payment, Wallet, Transaction, Issue, Points, Hunt, Domain, InviteFriend, UserProfile, IP, CompanyAdmin, Subscription, Company from .forms import FormInviteFriend, UserProfileForm, HuntForm from django.utils.timezone import make_aware +from decimal import Decimal +import stripe +import humanize def index(request, template="index.html"): try: @@ -75,6 +78,9 @@ def index(request, template="index.html"): domain_admin = CompanyAdmin.objects.get(user=request.user) except: domain_admin = None + wallet = None + if request.user.is_authenticated: + wallet = Wallet.objects.get(user=request.user) context = { 'activities': Issue.objects.all()[0:10], 'domains': domains, @@ -85,9 +91,10 @@ def index(request, template="index.html"): 'not_verified': show_message, #'open_issue_owasp': open_issue_owasp, #'closed_issue_owasp': closed_issue_owasp, - 'domain_admin' : domain_admin, + 'domain_admin': domain_admin, 'bug_count': bug_count, 'user_count': user_count, + 'wallet': wallet, 'hunt_count': hunt_count, 'domain_count': domain_count } @@ -95,23 +102,25 @@ def index(request, template="index.html"): @login_required(login_url='/accounts/login') def company_dashboard(request, template="index_company.html"): - - company_admin = CompanyAdmin.objects.get(user=request.user) - if not company_admin.is_active: - return HttpResponseRedirect("/") - hunts = Hunt.objects.filter(is_published=True,domain=company_admin.domain) - upcoming_hunt = list() - ongoing_hunt = list() - previous_hunt = list() - for hunt in hunts: - if((hunt.starts_on-datetime.now(timezone.utc)).total_seconds()) > 0: - upcoming_hunt.append(hunt) - elif((hunt.end_on-datetime.now(timezone.utc)).total_seconds()) < 0: - previous_hunt.append(hunt) - else: - ongoing_hunt.append(hunt) - context = {'upcoming_hunts': upcoming_hunt,'ongoing_hunt':ongoing_hunt,'previous_hunt':previous_hunt} - return render(request, template, context) + try: + company_admin = CompanyAdmin.objects.get(user=request.user) + if not company_admin.is_active: + return HttpResponseRedirect("/") + hunts = Hunt.objects.filter(is_published=True,domain=company_admin.domain) + upcoming_hunt = list() + ongoing_hunt = list() + previous_hunt = list() + for hunt in hunts: + if((hunt.starts_on-datetime.now(timezone.utc)).total_seconds()) > 0: + upcoming_hunt.append(hunt) + elif((hunt.end_on-datetime.now(timezone.utc)).total_seconds()) < 0: + previous_hunt.append(hunt) + else: + ongoing_hunt.append(hunt) + context = {'upcoming_hunts': upcoming_hunt,'ongoing_hunt':ongoing_hunt,'previous_hunt':previous_hunt} + return render(request, template, context) + except: + return redirect('/') @login_required(login_url='/accounts/login') def admin_company_dashboard(request, template="admin_dashboard_company.html"): @@ -150,7 +159,19 @@ def admin_dashboard(request, template="admin_home.html"): @login_required(login_url='/accounts/login') def user_dashboard(request, template="index_user.html"): - return render(request, template) + hunts = Hunt.objects.filter(is_published=True) + upcoming_hunt = list() + ongoing_hunt = list() + previous_hunt = list() + for hunt in hunts: + if((hunt.starts_on-datetime.now(timezone.utc)).total_seconds()) > 0: + upcoming_hunt.append(hunt) + elif((hunt.end_on-datetime.now(timezone.utc)).total_seconds()) < 0: + previous_hunt.append(hunt) + else: + ongoing_hunt.append(hunt) + context = {'upcoming_hunts': upcoming_hunt,'ongoing_hunt':ongoing_hunt,'previous_hunt':previous_hunt} + return render(request, template,context) def find_key(request, token): @@ -459,6 +480,8 @@ def form_valid(self, form): def get_context_data(self, **kwargs): context = super(IssueCreate, self).get_context_data(**kwargs) context['activities'] = Issue.objects.all()[0:10] + if self.request.user.is_authenticated: + context['wallet'] = Wallet.objects.get(user=self.request.user) context['hunts'] = Hunt.objects.exclude(plan="Free")[:4] context['leaderboard'] = User.objects.filter(points__created__month=datetime.now().month, points__created__year=datetime.now().year).annotate( @@ -527,17 +550,19 @@ def get_context_data(self, **kwargs): context['my_score'] = list(Points.objects.filter(user=self.object).aggregate(total_score=Sum('score')).values())[0] context['websites'] = Domain.objects.filter(issue__user=self.object).annotate(total=Count('issue')).order_by( '-total') - context['activities'] = Issue.objects.filter(user=self.object)[0:10] + context['activities'] = Issue.objects.filter(user=self.object, hunt=None)[0:10] context['profile_form'] = UserProfileForm() context['total_open'] = Issue.objects.filter(user=self.object, status="open").count() context['total_closed'] = Issue.objects.filter(user=self.object, status="closed").count() context['current_month'] = datetime.now().month + if self.request.user.is_authenticated: + context['wallet'] = Wallet.objects.get(user=self.request.user) context['graph'] = Issue.objects.filter(user=self.object).filter(created__month__gte=(datetime.now().month - 6), created__month__lte=datetime.now().month) \ .annotate(month=ExtractMonth('created')).values('month').annotate(c=Count('id')).order_by() - context['total_bugs'] = Issue.objects.filter(user=self.object).count() + context['total_bugs'] = Issue.objects.filter(user=self.object, hunt=None).count() for i in range(0, 7): - context['bug_type_' + str(i)] = Issue.objects.filter(user=self.object, label=str(i)) + context['bug_type_' + str(i)] = Issue.objects.filter(user=self.object, hunt=None, label=str(i)) arr = [] allFollowers = user.userprofile.follower.all() @@ -562,6 +587,7 @@ def post(self, request, *args, **kwargs): form.save() return redirect(reverse('profile', kwargs={'slug': kwargs.get('slug')})) + class UserProfileDetailsView(DetailView): model = get_user_model() slug_field = "username" @@ -569,7 +595,10 @@ class UserProfileDetailsView(DetailView): def get(self, request, *args, **kwargs): try: - self.object = self.get_object() + if request.user.is_authenticated: + self.object = self.get_object() + else: + return redirect("/accounts/login") except Http404: messages.error(self.request, 'That user was not found.') return redirect("/") @@ -581,18 +610,20 @@ def get_context_data(self, **kwargs): context['my_score'] = list(Points.objects.filter(user=self.object).aggregate(total_score=Sum('score')).values())[0] context['websites'] = Domain.objects.filter(issue__user=self.object).annotate(total=Count('issue')).order_by( '-total') - context['activities'] = Issue.objects.filter(user=self.object)[0:10] + if self.request.user.is_authenticated: + context['wallet'] = Wallet.objects.get(user=self.request.user) + context['activities'] = Issue.objects.filter(user=self.object, hunt=None)[0:10] context['profile_form'] = UserProfileForm() context['total_open'] = Issue.objects.filter(user=self.object, status="open").count() context['user_details'] = UserProfile.objects.get(user=self.object) context['total_closed'] = Issue.objects.filter(user=self.object, status="closed").count() context['current_month'] = datetime.now().month - context['graph'] = Issue.objects.filter(user=self.object).filter(created__month__gte=(datetime.now().month - 6), + context['graph'] = Issue.objects.filter(user=self.object, hunt=None).filter(created__month__gte=(datetime.now().month - 6), created__month__lte=datetime.now().month) \ .annotate(month=ExtractMonth('created')).values('month').annotate(c=Count('id')).order_by() context['total_bugs'] = Issue.objects.filter(user=self.object).count() for i in range(0, 7): - context['bug_type_' + str(i)] = Issue.objects.filter(user=self.object, label=str(i)) + context['bug_type_' + str(i)] = Issue.objects.filter(user=self.object, hunt=None, label=str(i)) arr = [] allFollowers = user.userprofile.follower.all() @@ -643,9 +674,11 @@ def get_context_data(self, *args, **kwargs): parsed_url = urlparse("http://" + self.kwargs['slug']) open_issue = Issue.objects.filter(domain__name__contains=self.kwargs['slug']).filter( - status="open") + status="open", hunt=None) close_issue = Issue.objects.filter(domain__name__contains=self.kwargs['slug']).filter( - status="closed") + status="closed", hunt=None) + if self.request.user.is_authenticated: + context['wallet'] = Wallet.objects.get(user=self.request.user) context['name'] = parsed_url.netloc.split(".")[-2:][0].title() @@ -679,10 +712,10 @@ def get_context_data(self, *args, **kwargs): context['leaderboard'] = User.objects.filter(issue__url__contains=self.kwargs['slug']).annotate( total=Count('issue')).order_by('-total') context['current_month'] = datetime.now().month - context['domain_graph'] = Issue.objects.filter(domain=context['domain']).filter( + context['domain_graph'] = Issue.objects.filter(domain=context['domain'], hunt=None).filter( created__month__gte=(datetime.now().month - 6), created__month__lte=datetime.now().month) \ .annotate(month=ExtractMonth('created')).values('month').annotate(c=Count('id')).order_by() - context['pie_chart'] = Issue.objects.filter(domain=context['domain']).values('label').annotate( + context['pie_chart'] = Issue.objects.filter(domain=context['domain'], hunt=None).values('label').annotate( c=Count('label')).order_by() return context @@ -698,6 +731,8 @@ def get_context_data(self, *args, **kwargs): for item in soup.findAll("span", {"class": "e-f-ih"}): stats = item.attrs['title'] + if self.request.user.is_authenticated: + context['wallet'] = Wallet.objects.get(user=self.request.user) context['extension_users'] = stats.replace(" users", "") context['bug_count'] = Issue.objects.all().count() context['user_count'] = User.objects.all().count() @@ -718,9 +753,9 @@ class AllIssuesView(ListView): def get_queryset(self): username = self.request.GET.get('user') if username is None: - self.activities = Issue.objects.all() + self.activities = Issue.objects.filter(hunt=None) else: - self.activities = Issue.objects.filter(user__username=username) + self.activities = Issue.objects.filter(user__username=username, hunt=None) return self.activities def get_context_data(self, *args, **kwargs): @@ -728,6 +763,8 @@ def get_context_data(self, *args, **kwargs): paginator = Paginator(self.activities, self.paginate_by) page = self.request.GET.get('page') + if self.request.user.is_authenticated: + context['wallet'] = Wallet.objects.get(user=self.request.user) try: activities_paginated = paginator.page(page) except PageNotAnInteger: @@ -770,11 +807,11 @@ def get_queryset(self): statu = 'closed'; if username is None: - self.activities = Issue.objects.all() + self.activities = Issue.objects.filter(hunt=None) elif statu != 'none': - self.activities = Issue.objects.filter(user__username=username, status=statu) + self.activities = Issue.objects.filter(user__username=username, status=statu, hunt=None) else: - self.activities = Issue.objects.filter(user__username=username, label=query) + self.activities = Issue.objects.filter(user__username=username, label=query, hunt=None) return self.activities def get_context_data(self, *args, **kwargs): @@ -782,6 +819,8 @@ def get_context_data(self, *args, **kwargs): paginator = Paginator(self.activities, self.paginate_by) page = self.request.GET.get('page') + if self.request.user.is_authenticated: + context['wallet'] = Wallet.objects.get(user=self.request.user) try: activities_paginated = paginator.page(page) except PageNotAnInteger: @@ -801,6 +840,9 @@ class LeaderboardView(ListView): def get_context_data(self, *args, **kwargs): context = super(LeaderboardView, self).get_context_data(*args, **kwargs) + + if self.request.user.is_authenticated: + context['wallet'] = Wallet.objects.get(user=self.request.user) context['leaderboard'] = User.objects.annotate(total_score=Sum('points__score')).order_by( '-total_score').filter(total_score__gt=0) return context @@ -817,6 +859,8 @@ def get_context_data(self, *args, **kwargs): paginator = Paginator(companies, self.paginate_by) page = self.request.GET.get('page') + if self.request.user.is_authenticated: + context['wallet'] = Wallet.objects.get(user=self.request.user) try: scoreboard_paginated = paginator.page(page) except PageNotAnInteger: @@ -850,27 +894,30 @@ def search(request, template="search.html"): context = { 'query': query, 'type': stype, - 'issues': Issue.objects.filter(Q(description__icontains=query))[0:20] + 'issues': Issue.objects.filter(Q(description__icontains=query), hunt=None)[0:20] } elif stype == "domain": context = { 'query': query, 'type': stype, - 'domains': Domain.objects.filter(Q(url__icontains=query))[0:20] + 'domains': Domain.objects.filter(Q(url__icontains=query), hunt=None)[0:20] } elif stype == "user": context = { 'query': query, 'type': stype, - 'users': UserProfile.objects.filter(Q(user__username__icontains=query)).annotate( + 'users': UserProfile.objects.filter(Q(user__username__icontains=query), hunt=None).annotate( total_score=Sum('user__points__score')).order_by('-total_score')[0:20] } elif stype == "label": context = { 'query': query, 'type': stype, - 'issues': Issue.objects.filter(Q(label__icontains=query))[0:20] + 'issues': Issue.objects.filter(Q(label__icontains=query), hunt=None)[0:20] } + + if request.user.is_authenticated: + context['wallet'] = Wallet.objects.get(user=request.user) return render(request, template, context) @@ -937,6 +984,9 @@ def get_context_data(self, **kwargs): context['os_version'] = user_agent.os.version_string context['users_score'] = \ list(Points.objects.filter(user=self.object.user).aggregate(total_score=Sum('score')).values())[0] + + if self.request.user.is_authenticated: + context['wallet'] = Wallet.objects.get(user=self.request.user) context['issue_count'] = Issue.objects.filter(url__contains=self.object.domain_name).count() context['all_comment'] = self.object.comments.all context['all_users'] = User.objects.all() @@ -973,6 +1023,8 @@ class EmailDetailView(TemplateView): def get_context_data(self, *args, **kwargs): context = super(EmailDetailView, self).get_context_data(*args, **kwargs) context['emails'] = get_email_from_domain(self.kwargs['slug']) + if self.request.user.is_authenticated: + context['wallet'] = Wallet.objects.get(user=self.request.user) return context @@ -1262,6 +1314,11 @@ def create_tokens(request): Token.objects.get_or_create(user=user) return JsonResponse("Created", safe=False) +def create_wallet(request): + for user in User.objects.all(): + Wallet.objects.get_or_create(user=user) + return JsonResponse("Created", safe=False) + def issue_count(request): open_issue = Issue.objects.filter(status="open").count() close_issue = Issue.objects.filter(status="closed").count() @@ -1433,6 +1490,10 @@ def post(self, request, *args, **kwargs): try: domain_admin = CompanyAdmin.objects.get(user=request.user) if (domain_admin.role == 1 and (str(domain_admin.domain.pk) == ((request.POST['domain']).split('-'))[0].replace(" ", ""))) or domain_admin.role == 0: + wallet = Wallet.objects.get(user=request.user) + total_amount = Decimal(request.POST['prize_winner']) + Decimal(request.POST['prize_runner']) + Decimal(request.POST['prize_second_runner']) + if total_amount > wallet.current_balance: + return HttpResponse("failed") hunt = Hunt() hunt.domain = Domain.objects.get(pk=(request.POST['domain']).split('-')[0].replace(" ", "")) data = {} @@ -1466,9 +1527,14 @@ def post(self, request, *args, **kwargs): hunt.starts_on = start_date # hunt.starts_on = make_aware(datetime.strptime(request.POST['date1'], '%Y-%m-%d %H:%M')) # hunt.end_on = make_aware(datetime.strptime(request.POST['date2'], '%Y-%m-%d %H:%M')) + hunt.prize_winner = Decimal(request.POST['prize_winner']) + hunt.prize_runner = Decimal(request.POST['prize_runner']) + hunt.prize_second_runner = Decimal(request.POST['prize_second_runner']) hunt.end_on = end_date hunt.name = request.POST['name'] hunt.description = request.POST['content'] + wallet.withdraw(total_amount) + wallet.save() try: is_published = request.POST['publish'] hunt.is_published = True @@ -1570,9 +1636,9 @@ def get(self, request, *args, **kwargs): if((hunt.starts_on-datetime.now(timezone.utc)).total_seconds()) > 0: pass elif((hunt.end_on-datetime.now(timezone.utc)).total_seconds()) < 0: - pass - else: new_hunt.append(hunt) + else: + pass context = {'hunts': new_hunt} return render(request, self.template_name, context) except: @@ -1690,31 +1756,63 @@ def add_role(request): @login_required(login_url='/accounts/login') def add_or_update_company(request): user = request.user + for key, value in request.POST.items(): + print('Key: %s' % (key) ) + # print(f'Key: {key}') in Python >= 3.7 + print('Value %s' % (value) ) if(user.is_superuser): if not user.is_active: return HttpResponseRedirect("/") if request.method == "POST": + + domain_pk = request.POST['id'] + company = Company.objects.get(pk=domain_pk) + user = company.admin + if(user!=User.objects.get(email=request.POST['admin'])): + try: + admin = CompanyAdmin.objects.get(user=user, company=company) + admin.user = User.objects.get(email=request.POST['admin']) + admin.save() + except: + admin = CompanyAdmin() + admin.user = User.objects.get(email=request.POST['admin']) + admin.role = 0 + admin.company = company + admin.is_active = True + admin.save() + company.name = request.POST['name'] + company.email = request.POST['email'] + company.url = request.POST['url'] + company.admin = User.objects.get(email=request.POST['admin']) + company.github = request.POST['github'] try: - domain_pk = request.POST['id'] - company = Company.objects.get(pk=domain_pk) - user = company.admin - if(user!=User.objects.get(email=request.POST['admin'])): - try: - admin = CompanyAdmin.objects.get(user=user, company=company) - admin.user = User.objects.get(email=request.POST['admin']) - admin.save() - except: - admin = CompanyAdmin() - admin.user = User.objects.get(email=request.POST['admin']) - admin.role = 0 - admin.company = company - admin.is_active = True - admin.save() + is_verified =request.POST['verify'] + print(is_verified) + if is_verified=='on': + company.is_active = True + else: + company.is_active = False + except: + company.is_active = False + try: + company.subscription = Subscription.objects.get(name=request.POST['subscription']) + except: + pass + try: + company.logo = request.FILES['logo'] + except: + pass + company.save() + return HttpResponse("success") + try: + company = Company() company.name = request.POST['name'] company.email = request.POST['email'] company.url = request.POST['url'] company.admin = User.objects.get(email=request.POST['admin']) company.github = request.POST['github'] + if request.POST['verify']=='true': + company.is_active = request.POST['verify'] try: company.subscription = Subscription.objects.get(name=request.POST['subscription']) except: @@ -1724,33 +1822,15 @@ def add_or_update_company(request): except: pass company.save() - return HttpResponse("success") + admin = CompanyAdmin() + admin.user = User.objects.get(email=request.POST['admin']) + admin.role = 0 + admin.company = company + admin.is_active = True + admin.save() + return HttpResponse("success") except: - try: - company = Company() - company.name = request.POST['name'] - company.email = request.POST['email'] - company.url = request.POST['url'] - company.admin = User.objects.get(email=request.POST['admin']) - company.github = request.POST['github'] - try: - company.subscription = Subscription.objects.get(name=request.POST['subscription']) - except: - pass - try: - company.logo = request.FILES['logo'] - except: - pass - company.save() - admin = CompanyAdmin() - admin.user = User.objects.get(email=request.POST['admin']) - admin.role = 0 - admin.company = company - admin.is_active = True - admin.save() - return HttpResponse("success") - except: - return HttpResponse("failed") + return HttpResponse("failed") else: return HttpResponse("failed") else: @@ -1915,3 +1995,379 @@ def company_dashboard_hunt_edit(request, pk, template="company_dashboard_hunt_ed hunt.is_published = False hunt.save() return HttpResponse("success") + + +@login_required(login_url='/accounts/login') +def withdraw(request): + print("WITHDRAWING") + if request.method == "POST": + if request.user.is_authenticated: + wallet = Wallet.objects.get(user=request.user) + if(wallet.current_balance payment.value*100: + stripe.Transfer.create( + amount=Decimal(request.POST['amount'])*100, + currency="usd", + destination=wallet.account_id, + transfer_group="ORDER_95", + ) + wallet.withdraw(Decimal(request.POST['amount'])) + wallet.save() + payment.active = False + payment.save() + return HttpResponseRedirect("/dashboard/user/profile/"+request.user.username) + else: + return HttpResponse("INSUFFICIENT BALANCE") + else: + wallet.account_id=None + wallet.save() + account = stripe.Account.create( + type='express', + ) + wallet.account_id = account.id + wallet.save() + account_links = stripe.AccountLink.create( + account=account, + return_url='http://127.0.0.1:8000/dashboard/user/stripe/connected/'+request.user.username, + refresh_url='http://127.0.0.1:8000/dashboard/user/profile/'+request.user.username, + type='account_onboarding', + ) + print(account_links) + return JsonResponse({'redirect': account_links.url, 'status': 'success'}) + else: + account = stripe.Account.create( + type='express', + ) + wallet.account_id = account.id + wallet.save() + account_links = stripe.AccountLink.create( + account=account, + return_url='http://127.0.0.1:8000/dashboard/user/stripe/connected/'+request.user.username, + refresh_url='http://127.0.0.1:8000/dashboard/user/profile/'+request.user.username, + type='account_onboarding', + ) + print(account_links) + return JsonResponse({'redirect': account_links.url, 'status': 'success'}) + return JsonResponse({'status': 'error'}) + +@login_required(login_url='/accounts/login') +def addbalance(request): + if request.method == "POST": + if request.user.is_authenticated: + for key, value in request.POST.items(): + print('Key: %s' % (key) ) + # print(f'Key: {key}') in Python >= 3.7 + print('Value %s' % (value) ) + wallet = Wallet.objects.get(user=request.user) + from django.conf import settings + stripe.api_key = settings.STRIPE_TEST_SECRET_KEY + charge = stripe.Charge.create( + amount=int(Decimal(request.POST['amount'])*100), + currency='usd', + description='Example charge', + source=request.POST['stripeToken'], + ) + wallet.deposit(request.POST['amount']) + print(charge) + return HttpResponse("success") + +@login_required(login_url='/accounts/login') +def stripe_connected(request, username): + user = User.objects.get(username = username) + wallet = Wallet.objects.get(user = user) + from django.conf import settings + stripe.api_key = settings.STRIPE_TEST_SECRET_KEY + account = stripe.Account.retrieve(wallet.account_id) + if account.payouts_enabled==True: + payment = Payment.objects.get(wallet=wallet, active=True) + balance = stripe.Balance.retrieve() + if balance.available[0].amount > payment.value*100: + stripe.Transfer.create( + amount=payment.value*100, + currency="usd", + destination="000123456789", + transfer_group="ORDER_95", + ) + wallet.withdraw(Decimal(request.POST['amount'])) + wallet.save() + payment.active = False + payment.save() + return HttpResponseRedirect("/dashboard/user/profile/"+username) + else: + return HttpResponse("ERROR") + else: + wallet.account_id=None + wallet.save() + return HttpResponse("error") + + +class JoinCompany(TemplateView): + model = Company + # fields = ['url', 'logo', 'domain', 'plan', 'prize', 'txn_id'] + template_name = "join.html" + + @method_decorator(login_required) + def get(self, request, *args, **kwargs): + # try: + wallet = Wallet.objects.get(user=request.user) + context = {'wallet': wallet} + # return render(request, self.template_name, context) + return render(request, self.template_name, context) + # except: + # return HttpResponseRedirect("/") + + def post(self, request, *args, **kwargs): + name = request.POST['company'] + try: + company_exists = Company.objects.get(name=name) + return JsonResponse({'status': 'There was some error'}) + except: + pass + url = request.POST['url'] + email = request.POST['email'] + product = request.POST['product'] + sub = Subscription.objects.get(name=product) + if name == '' or url == '' or email == '' or product =='' : + return JsonResponse({'error': 'Empty Fields'}) + paymentType = request.POST['paymentType'] + if paymentType == 'wallet': + wallet = Wallet.objects.get(user=request.user) + if wallet.current_balance < sub.charge_per_month: + return JsonResponse({'error': 'insufficient balance in Wallet'}) + wallet.withdraw(sub.charge_per_month) + company = Company() + company.admin = request.user + company.name = name + company.url = url + company.email = email + company.subscription = sub + company.save() + admin = CompanyAdmin() + admin.user = request.user + admin.role = 0 + admin.company = company + admin.is_active = True + admin.save() + return JsonResponse({'status': 'Success'}) + # company.subscription = + elif paymentType == 'card': + from django.conf import settings + stripe.api_key = settings.STRIPE_TEST_SECRET_KEY + charge = stripe.Charge.create( + amount=int(Decimal(sub.charge_per_month)*100), + currency='usd', + description='Example charge', + source=request.POST['stripeToken'], + ) + print(charge) + company = Company() + company.admin = request.user + company.name = name + company.url = url + company.email = email + company.subscription = sub + company.save() + admin = CompanyAdmin() + admin.user = request.user + admin.role = 0 + admin.company = company + admin.is_active = True + admin.save() + return JsonResponse({'status': 'Success'}) + else: + return JsonResponse({'status': 'There was some error'}) + + +@login_required(login_url='/accounts/login') +def view_hunt(request, pk, template="view_hunt.html"): + hunt = get_object_or_404(Hunt, pk=pk) + time_remaining = None + if((hunt.starts_on-datetime.now(timezone.utc)).total_seconds()) > 0: + hunt_active = False + hunt_completed = False + time_remaining = humanize.naturaltime(datetime.now(timezone.utc)-hunt.starts_on) + elif((hunt.end_on-datetime.now(timezone.utc)).total_seconds()) < 0: + hunt_active = False + hunt_completed = True + else: + hunt_active = True + hunt_completed = False + return render(request, template, {'hunt': hunt, 'hunt_completed': hunt_completed,'time_remaining': time_remaining, 'hunt_active': hunt_active}) + + +@login_required(login_url='/accounts/login') +def submit_bug(request, pk, template="hunt_submittion.html"): + hunt = get_object_or_404(Hunt, pk=pk) + time_remaining = None + if request.method == 'GET': + if((hunt.starts_on-datetime.now(timezone.utc)).total_seconds()) > 0: + return redirect('/dashboard/user/hunt/'+str(pk)+'/') + elif((hunt.end_on-datetime.now(timezone.utc)).total_seconds()) < 0: + return redirect('/dashboard/user/hunt/'+str(pk)+'/') + else: + return render(request, template, {'hunt': hunt}) + elif request.method == 'POST': + if((hunt.starts_on-datetime.now(timezone.utc)).total_seconds()) > 0: + return redirect('/dashboard/user/hunt/'+str(pk)+'/') + elif((hunt.end_on-datetime.now(timezone.utc)).total_seconds()) < 0: + return redirect('/dashboard/user/hunt/'+str(pk)+'/') + else: + url = request.POST['url'] + description = request.POST['description'] + if url=='' or description == '' : + issue_list = Issue.objects.filter(user=request.user, hunt=hunt) + return render(request, template, {'hunt': hunt, 'issue_list':issue_list}) + parsed_url = urlparse(url) + if parsed_url.scheme == '': + url = 'https://' + url + parsed_url = urlparse(url) + if parsed_url.netloc == '': + issue_list = Issue.objects.filter(user=request.user, hunt=hunt) + return render(request, template, {'hunt': hunt, 'issue_list':issue_list}) + label = request.POST['label'] + if request.POST.get('file'): + if isinstance(request.POST.get('file'), six.string_types): + import imghdr + # Check if the base64 string is in the "data:" format + data = "data:image/"+ request.POST.get('type') + ";base64," + request.POST.get('file') + data = data.replace(" ", "") + data += "=" * ((4 - len(data) % 4) % 4) + if 'data:' in data and ';base64,' in data: + # Break out the header from the base64 content + header, data = data.split(';base64,') + + # Try to decode the file. Return validation error if it fails. + try: + decoded_file = base64.b64decode(data) + except TypeError: + TypeError('invalid_image') + + # Generate file name: + file_name = str(uuid.uuid4())[:12] # 12 characters are more than enough. + # Get the file name extension: + extension = imghdr.what(file_name, decoded_file) + extension = "jpg" if extension == "jpeg" else extension + file_extension = extension + + complete_file_name = "%s.%s" % (file_name, file_extension, ) + + request.FILES['screenshot'] = ContentFile(decoded_file, name=complete_file_name) + issue = Issue() + issue.label = label + print(url) + issue.url = url + issue.user = request.user + issue.description = description + try: + issue.screenshot = request.FILES['screenshot'] + except: + print("IN HERE") + issue_list = Issue.objects.filter(user=request.user, hunt=hunt) + return render(request, template, {'hunt': hunt, 'issue_list':issue_list}) + issue.hunt = hunt + issue.save() + issue_list = Issue.objects.filter(user=request.user, hunt=hunt) + return render(request, template, {'hunt': hunt, 'issue_list':issue_list}) + +@login_required(login_url='/accounts/login') +def hunt_results(request, pk, template="hunt_results.html"): + hunt = get_object_or_404(Hunt, pk=pk) + return render(request, template, {'hunt': hunt}) + +@login_required(login_url='/accounts/login') +def company_hunt_results(request, pk, template="company_hunt_results.html"): + hunt = get_object_or_404(Hunt, pk=pk) + issues = Issue.objects.filter(hunt=hunt) + context = {} + if request.method == "GET": + context['hunt'] = get_object_or_404(Hunt, pk=pk) + context['issues'] = Issue.objects.filter(hunt=hunt) + if hunt.result_published: + context['winner'] = Winner.objects.get(hunt=hunt) + return render(request, template, context) + else: + for issue in issues: + issue.verified = False + issue.score = 0 + issue.save() + for key, value in request.POST.items(): + if key != 'csrfmiddlewaretoken' and key!='submit' and key!='checkAll': + submit_type = key.split('_')[0] + issue_id = key.split('_')[1] + issue = Issue.objects.get(pk=issue_id) + if issue.hunt==hunt and submit_type =='item': + if value == 'on': + issue.verified = True + elif issue.hunt==hunt and submit_type == 'value': + if value != '': + issue.score = int(value) + try: + if request.POST['checkAll']: + issue.verified = True + except: + pass + issue.save() + print(issue.verified) + print("issue.verified") + if request.POST['submit'] == 'save': + pass + if request.POST['submit'] == 'publish': + issue.save() + index = 1 + winner = Winner() + issue_with_score = Issue.objects.filter(hunt=hunt, verified=True).values('user').order_by('user').annotate(total_score=Sum('score')) + for obj in issue_with_score: + user = User.objects.get(pk=obj['user']) + if index == 1: + winner.winner = user + if index == 2: + winner.runner = user + if index == 3: + winner.second_runner = user + if index == 4: + break + index = index + 1 + total_amount = Decimal(hunt.prize_winner) + Decimal(hunt.prize_runner) + Decimal(hunt.prize_second_runner) + from django.conf import settings + stripe.api_key = settings.STRIPE_TEST_SECRET_KEY + balance = stripe.Balance.retrieve() + if balance.available[0].amount > total_amount*100: + if winner.winner: + wallet = Wallet.objects.get(user=winner.winner) + wallet.deposit(hunt.prize_winner) + wallet.save() + if winner.runner: + wallet = Wallet.objects.get(user=winner.runner) + wallet.deposit(hunt.prize_runner) + wallet.save() + if winner.second_runner: + wallet = Wallet.objects.get(user=winner.second_runner) + wallet.deposit(hunt.prize_second_runner) + wallet.save() + winner.prize_distributed = True + winner.hunt = hunt + winner.save() + hunt.result_published = True + hunt.save() + context['winner'] = winner + context['hunt'] = get_object_or_404(Hunt, pk=pk) + context['issues'] = Issue.objects.filter(hunt=hunt) + return render(request, template, context) \ No newline at end of file