From 2f4f2d8bd105c9f92d49d8d4fb867cc3c5fbd3c4 Mon Sep 17 00:00:00 2001 From: Miguel Dorado Date: Mon, 11 Feb 2019 09:50:52 +0800 Subject: [PATCH 01/17] created template for forget password --- .gitignore | 1 + assets/src/app/app.component.html | 6 +++ assets/src/app/app.component.ts | 1 + templates/base.html | 52 +++++++++++++++++++ .../registration/password_reset_complete.html | 13 +++++ .../registration/password_reset_confirm.html | 37 +++++++++++++ .../registration/password_reset_done.html | 13 +++++ .../registration/password_reset_form.html | 36 +++++++++++++ users/urls.py | 10 +++- users/views.py | 10 ++++ 10 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 templates/registration/password_reset_complete.html create mode 100644 templates/registration/password_reset_confirm.html create mode 100644 templates/registration/password_reset_done.html create mode 100644 templates/registration/password_reset_form.html diff --git a/.gitignore b/.gitignore index 9006ab5..f1323d1 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ static/ __pycache__/ env/ node_modules/ +themes/ \ No newline at end of file diff --git a/assets/src/app/app.component.html b/assets/src/app/app.component.html index fa87238..e5fe93c 100644 --- a/assets/src/app/app.component.html +++ b/assets/src/app/app.component.html @@ -54,6 +54,12 @@

+ +
diff --git a/assets/src/app/app.component.ts b/assets/src/app/app.component.ts index 5ac9619..382bd70 100644 --- a/assets/src/app/app.component.ts +++ b/assets/src/app/app.component.ts @@ -15,6 +15,7 @@ export class AppComponent implements OnInit { usersForm; errors; rememberMe:boolean = false; + forgetPasswordUrl = "http://localhost:8000/user/password_reset/"; constructor( private authService: AuthService, diff --git a/templates/base.html b/templates/base.html index e69de29..88bc7f0 100644 --- a/templates/base.html +++ b/templates/base.html @@ -0,0 +1,52 @@ +{% load static %} + + + + + + + + + + + + + + + + + + + {% block title %} + Marketplace + {% endblock title %} + + + + +
+ {% block content %} + + {% endblock content %} +
+ + + + + + + + + + \ No newline at end of file diff --git a/templates/registration/password_reset_complete.html b/templates/registration/password_reset_complete.html new file mode 100644 index 0000000..11aa7c5 --- /dev/null +++ b/templates/registration/password_reset_complete.html @@ -0,0 +1,13 @@ +{% extends 'base.html' %} +{% load il8n %} + +{% block content %} +
+
+

Forget your password?

+

+ {% trans "Your password has been set. Return to homepage to log " %} +

+
+
+{% endblock content %} \ No newline at end of file diff --git a/templates/registration/password_reset_confirm.html b/templates/registration/password_reset_confirm.html new file mode 100644 index 0000000..414ec27 --- /dev/null +++ b/templates/registration/password_reset_confirm.html @@ -0,0 +1,37 @@ +{% extends 'base.html' %} +{% load i18n %} + +{% block content %} +{% if validlink %} +
+
+

Forget your password?

+

+ {% trans "Please enter your new password twice so we can verify you typed it in correctly." %} +

+
+ +
+ {% csrf_token %} +
+
+ {{ form.new_password1.errors }} + + {{ form.new_password1 }} +
+
+ {{ form.new_password2.errors }} + + {{ form.new_password2 }} +
+ +
+
+
+ +{% else%} +

{% trans "The password reset link was invalid, possibly because it has already been used. Please request a new password reset." %}

+ +{% endif %} + +{% endblock %} \ No newline at end of file diff --git a/templates/registration/password_reset_done.html b/templates/registration/password_reset_done.html new file mode 100644 index 0000000..57a9276 --- /dev/null +++ b/templates/registration/password_reset_done.html @@ -0,0 +1,13 @@ +{% extends 'base.html' %} +{% load i18n %} + +{% block content %} +
+

{% trans "We've emailed you instructions for setting your password, if an account exists with the email you entered. You should receive them shortly." %}

+ +

{% trans "If you don't receive an email, please make sure you've entered the address you registered with, and check your spam folder." %}

+
+ Go to Homepage + +
+{% endblock content %} \ No newline at end of file diff --git a/templates/registration/password_reset_form.html b/templates/registration/password_reset_form.html new file mode 100644 index 0000000..daa58f2 --- /dev/null +++ b/templates/registration/password_reset_form.html @@ -0,0 +1,36 @@ +{% extends 'base.html' %} +{% load widget_tweaks %} + +{% block title %} +Forget Password - Marketplace +{% endblock title %} + +{% block content %} +
+
+

Forget your password?

+

+ Please enter your email address, we will respond with instructions to reset your password. +

+
+
+
+ {% csrf_token %} +
+
+ + + {{ form.email|add_class:"form-control"|attr:"placeholder:example@example.com" }} + + {{ form.email.errors }} + + +
+ +
+ +
+
+
+ +{% endblock content %} \ No newline at end of file diff --git a/users/urls.py b/users/urls.py index 3b1f842..f3742b5 100644 --- a/users/urls.py +++ b/users/urls.py @@ -1,4 +1,5 @@ -from django.urls import path, include +from django.urls import path, include, re_path +from django.contrib.auth import views as auth_views from . import views from rest_framework import routers @@ -7,4 +8,11 @@ path('register/', views.Register.as_view()), path('refresh/',views.RefreshToken.as_view()), path('auth/', include('rest_framework.urls', namespace='rest_framework')), + + # forget password links + path('password_reset/', auth_views.PasswordResetView.as_view(), name='password_reset'), + path('password_reset/done/', auth_views.PasswordResetDoneView.as_view(), name='password_reset_done'), + re_path(r'^reset/(?P[0-9A-Za-z_\-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', + auth_views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'), + path('reset/done/', auth_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'), ] diff --git a/users/views.py b/users/views.py index d236539..459f135 100644 --- a/users/views.py +++ b/users/views.py @@ -6,6 +6,7 @@ from .serializers import LoginSerializer, RegisterSerializer from .managers import UserManager from rest_framework.exceptions import ValidationError +from django.contrib.auth.views import PasswordResetView from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import parsers, renderers @@ -74,6 +75,15 @@ def get(self,request,*args,**kwargs): }, status=200, headers={'Authorization': 'Token {}'.format(token.key)}) +# class SendEmailToken(APIView): +# """send and email containing a url with expiration +# for redirecting to the forget password page +# """ +# permission_classes = (AllowAny,) + +# def + + From ba3adaf795c07cbe01660142e9f45ee84a86f439 Mon Sep 17 00:00:00 2001 From: Miguel Dorado Date: Mon, 11 Feb 2019 10:44:27 +0800 Subject: [PATCH 02/17] setup default smtp default backend for testing --- market/settings.py | 2 ++ templates/registration/password_reset_email.html | 12 ++++++++++++ templates/registration/password_reset_subject.txt | 3 +++ 3 files changed, 17 insertions(+) create mode 100644 templates/registration/password_reset_email.html create mode 100644 templates/registration/password_reset_subject.txt diff --git a/market/settings.py b/market/settings.py index 1b91af0..80deed8 100644 --- a/market/settings.py +++ b/market/settings.py @@ -159,6 +159,8 @@ os.path.join(BASE_DIR, 'assets/'), ] +EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' + # Allow any settings to be defined in local_settings.py which should be # ignored in your version control system allowing for settings to be # defined per machine. diff --git a/templates/registration/password_reset_email.html b/templates/registration/password_reset_email.html new file mode 100644 index 0000000..2a55eee --- /dev/null +++ b/templates/registration/password_reset_email.html @@ -0,0 +1,12 @@ +{% autoescape off %} +To initiate the password reset process for your {{ user.get_username }} Swiftkind Market Account, +click the link below: + +{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %} + +If clicking the link above doesn't work, please copy and paste the URL in a new browser +window instead. + +Sincerely, +The Swiftkind Team +{% endautoescape %} \ No newline at end of file diff --git a/templates/registration/password_reset_subject.txt b/templates/registration/password_reset_subject.txt new file mode 100644 index 0000000..45a354b --- /dev/null +++ b/templates/registration/password_reset_subject.txt @@ -0,0 +1,3 @@ +{% load i18n %}{% autoescape off %} +{% blocktrans %}Password reset on {{ site_name }}{% endblocktrans %} +{% endautoescape %} \ No newline at end of file From 683d6391262d09ee45457139b948f995837842da Mon Sep 17 00:00:00 2001 From: Miguel Dorado Date: Mon, 11 Feb 2019 11:18:19 +0800 Subject: [PATCH 03/17] removed comments --- .../registration/password_reset_confirm.html | 43 +++++++++++-------- .../registration/password_reset_form.html | 1 - users/views.py | 9 ---- 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/templates/registration/password_reset_confirm.html b/templates/registration/password_reset_confirm.html index 414ec27..a589a25 100644 --- a/templates/registration/password_reset_confirm.html +++ b/templates/registration/password_reset_confirm.html @@ -1,4 +1,5 @@ {% extends 'base.html' %} +{% load widget_tweaks %} {% load i18n %} {% block content %} @@ -10,23 +11,31 @@

{% trans "Please enter your new password twice so we can verify you typed it in correctly." %}

- -
- {% csrf_token %} -
-
- {{ form.new_password1.errors }} - - {{ form.new_password1 }} -
-
- {{ form.new_password2.errors }} - - {{ form.new_password2 }} -
- -
-
+
+
+
+ {% csrf_token %} +
+
+ + {{ form.new_password1.errors }} + + + {{ form.new_password1|add_class:"form-control"|attr:"type:text"|attr:"placeholder:New password" }} +
+
+ + {{ form.new_password2.errors }} + + + {{ form.new_password2|add_class:"form-control"|attr:"type:text"|attr:"placeholder:Confirm password"}} +
+ + +
+
+
+
{% else%} diff --git a/templates/registration/password_reset_form.html b/templates/registration/password_reset_form.html index daa58f2..4028578 100644 --- a/templates/registration/password_reset_form.html +++ b/templates/registration/password_reset_form.html @@ -19,7 +19,6 @@

- {{ form.email|add_class:"form-control"|attr:"placeholder:example@example.com" }} {{ form.email.errors }} diff --git a/users/views.py b/users/views.py index 459f135..c3cf6ab 100644 --- a/users/views.py +++ b/users/views.py @@ -75,15 +75,6 @@ def get(self,request,*args,**kwargs): }, status=200, headers={'Authorization': 'Token {}'.format(token.key)}) -# class SendEmailToken(APIView): -# """send and email containing a url with expiration -# for redirecting to the forget password page -# """ -# permission_classes = (AllowAny,) - -# def - - From ddc839efef0739a2669eb9911b3422381279dbd5 Mon Sep 17 00:00:00 2001 From: Miguel Dorado Date: Mon, 11 Feb 2019 17:40:39 +0800 Subject: [PATCH 04/17] can download compressed file of theme template just by clicking pay with paypal, Paypal payment method not yet included --- .gitignore | 3 ++- assets/src/app/app.component.ts | 3 ++- .../app/commons/services/auth/auth.service.ts | 7 ++++--- .../app/commons/services/cart/cart.service.ts | 20 ++++++++++++++++++- .../services/details/details.service.ts | 5 +++-- .../app/commons/services/home/home.service.ts | 5 +++-- .../app/components/cart/cart.component.html | 14 +++++++------ .../src/app/components/cart/cart.component.ts | 16 +++++++++++++++ .../components/details/details.component.html | 4 ++-- .../components/details/details.component.ts | 1 + .../src/app/components/home/home.component.ts | 3 ++- details/urls.py | 1 + details/views.py | 18 +++++++++++++++++ market/settings.py | 2 +- themes/models.py | 6 +++++- themes/views.py | 9 +++++++-- 16 files changed, 94 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index f1323d1..e075ae2 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ static/ __pycache__/ env/ node_modules/ -themes/ \ No newline at end of file +themes/ +demo/ \ No newline at end of file diff --git a/assets/src/app/app.component.ts b/assets/src/app/app.component.ts index 382bd70..05d029f 100644 --- a/assets/src/app/app.component.ts +++ b/assets/src/app/app.component.ts @@ -15,7 +15,8 @@ export class AppComponent implements OnInit { usersForm; errors; rememberMe:boolean = false; - forgetPasswordUrl = "http://localhost:8000/user/password_reset/"; + domain_url = '192.168.2.30'; + forgetPasswordUrl = "http://"+this.domain_url+":8000/user/password_reset/"; constructor( private authService: AuthService, diff --git a/assets/src/app/commons/services/auth/auth.service.ts b/assets/src/app/commons/services/auth/auth.service.ts index 792ca97..efa38be 100644 --- a/assets/src/app/commons/services/auth/auth.service.ts +++ b/assets/src/app/commons/services/auth/auth.service.ts @@ -8,13 +8,14 @@ export class AuthService { rememberMe:boolean; token; user; + domain_url = '192.168.2.30'; constructor(private http: HttpClient) { } // Generate token upon login loginAuth(user,remember){ this.rememberMe = remember; this.user = user; - return this.http.post("http://localhost:8000/user/login/", user) + return this.http.post("http://"+this.domain_url+":8000/user/login/", user) .toPromise() .then( response => { @@ -31,7 +32,7 @@ export class AuthService { // Generate token upon register registerAuth(user){ - return this.http.post("http://localhost:8000/user/register/", user) + return this.http.post("http://"+this.domain_url+"/user/register/", user) .toPromise() .then( response => { @@ -44,7 +45,7 @@ export class AuthService { } refreshToken(user){ - return this.http.get("http://localhost:8000/user/refresh/", user) + return this.http.get("http://"+this.domain_url+"localhost:8000/user/refresh/", user) .toPromise() .then( response => { diff --git a/assets/src/app/commons/services/cart/cart.service.ts b/assets/src/app/commons/services/cart/cart.service.ts index f202955..126347e 100644 --- a/assets/src/app/commons/services/cart/cart.service.ts +++ b/assets/src/app/commons/services/cart/cart.service.ts @@ -7,11 +7,13 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; export class CartService { httpHeaders = new HttpHeaders({'Content-type':'application/json'}); + domain_url = '192.168.2.30'; + constructor( private http: HttpClient) { } getThemeCart(id){ - return this.http.get('http://localhost:8000/home/theme/cart/'+id+'/', {headers: this.httpHeaders}) + return this.http.get('http://'+this.domain_url+':8000/home/theme/cart/'+id+'/', {headers: this.httpHeaders}) .toPromise() .then( response => { @@ -24,4 +26,20 @@ export class CartService { } ) } + + buyThemeService(id){ + return this.http.get('http://'+this.domain_url+':8000/details/download/'+id+'/', {headers: this.httpHeaders}) + .toPromise() + .then( + response => { + return response; + } + ) + .catch( + error => { + return error; + } + ) + + } } diff --git a/assets/src/app/commons/services/details/details.service.ts b/assets/src/app/commons/services/details/details.service.ts index 7762845..341226f 100644 --- a/assets/src/app/commons/services/details/details.service.ts +++ b/assets/src/app/commons/services/details/details.service.ts @@ -6,12 +6,13 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; }) export class DetailsService { + domain_url = '192.168.2.30'; httpHeaders = new HttpHeaders({'Content-type': 'application/json'}); constructor( private http: HttpClient) { } getThemeDetailsService(id){ - return this.http.get('http://localhost:8000/home/theme/details/'+id+'/', {headers: this.httpHeaders}) + return this.http.get('http://'+this.domain_url+':8000/home/theme/details/'+id+'/', {headers: this.httpHeaders}) .toPromise() .then( response =>{ @@ -26,7 +27,7 @@ export class DetailsService { } createReviewService(comment){ - return this.http.post("http://localhost:8000/details/createReview/",comment) + return this.http.post("http://"+this.domain_url+":8000/details/createReview/",comment) .toPromise() .then( response => { diff --git a/assets/src/app/commons/services/home/home.service.ts b/assets/src/app/commons/services/home/home.service.ts index d9b62c2..b32c43d 100644 --- a/assets/src/app/commons/services/home/home.service.ts +++ b/assets/src/app/commons/services/home/home.service.ts @@ -7,6 +7,7 @@ import { Observable } from 'rxjs'; }) export class HomeService { + domain_url = '192.168.2.30'; httpHeaders = new HttpHeaders({'Content-type': 'application/json'}); public categories; constructor(private http: HttpClient) { @@ -14,7 +15,7 @@ export class HomeService { } getThemes(){ - return this.http.get("http://localhost:8000/home/theme/", {headers: this.httpHeaders}) + return this.http.get("http://"+this.domain_url+":8000/home/theme/", {headers: this.httpHeaders}) .toPromise() .then( response => { @@ -29,7 +30,7 @@ export class HomeService { } getCategory(){ - return this.http.get("http://localhost:8000/home/theme/category/", {headers: this.httpHeaders}) + return this.http.get("http://"+this.domain_url+":8000/home/theme/category/", {headers: this.httpHeaders}) .toPromise() .then( response => { diff --git a/assets/src/app/components/cart/cart.component.html b/assets/src/app/components/cart/cart.component.html index e398c47..45cca5c 100644 --- a/assets/src/app/components/cart/cart.component.html +++ b/assets/src/app/components/cart/cart.component.html @@ -2,7 +2,7 @@
diff --git a/assets/src/app/components/cart/cart.component.ts b/assets/src/app/components/cart/cart.component.ts index 735e6cd..0985d83 100644 --- a/assets/src/app/components/cart/cart.component.ts +++ b/assets/src/app/components/cart/cart.component.ts @@ -13,6 +13,7 @@ export class CartComponent implements OnInit { theme; discount; dis_price; + domain_url = '192.168.2.30'; constructor( private cartService: CartService, private route: ActivatedRoute, @@ -51,6 +52,21 @@ export class CartComponent implements OnInit { ) } + buyTheme(event,theme_id){ + console.log('clicked'); + this.cartService.buyThemeService(theme_id) + .then( + response => { + return response; + } + ) + .catch( + error => { + return error; + } + ) + } + } diff --git a/assets/src/app/components/details/details.component.html b/assets/src/app/components/details/details.component.html index bcd60f4..16578e8 100644 --- a/assets/src/app/components/details/details.component.html +++ b/assets/src/app/components/details/details.component.html @@ -22,7 +22,7 @@
{{ theme.name }}
- +
@@ -108,7 +108,7 @@

{{ theme.name }}

Screenshots

- +
diff --git a/assets/src/app/components/details/details.component.ts b/assets/src/app/components/details/details.component.ts index 6565c90..204a13a 100644 --- a/assets/src/app/components/details/details.component.ts +++ b/assets/src/app/components/details/details.component.ts @@ -19,6 +19,7 @@ export class DetailsComponent implements OnInit { reviews; content; token; + domain_url = '192.168.2.30'; constructor( private route: ActivatedRoute, diff --git a/assets/src/app/components/home/home.component.ts b/assets/src/app/components/home/home.component.ts index 222f831..1c7c293 100644 --- a/assets/src/app/components/home/home.component.ts +++ b/assets/src/app/components/home/home.component.ts @@ -17,7 +17,8 @@ export class HomeComponent implements OnInit { themes; category; searchCategory; - baseUrl = "http://localhost:8000/media/"; + domain_url = '192.168.2.30'; + baseUrl = "http://"+this.domain_url+":8000/media/"; constructor( diff --git a/details/urls.py b/details/urls.py index 5be5e0b..cb93a3d 100644 --- a/details/urls.py +++ b/details/urls.py @@ -3,4 +3,5 @@ urlpatterns = [ path('createReview/', views.CreateReview.as_view()), + path('download//',views.DownloadTheme.as_view()), ] \ No newline at end of file diff --git a/details/views.py b/details/views.py index cf8415e..f9cee80 100644 --- a/details/views.py +++ b/details/views.py @@ -6,6 +6,11 @@ from rest_framework.response import Response from .serializers import ReviewSerializer from rest_framework.authtoken.models import Token +from django.views.generic import View +from io import StringIO +from zipfile import ZipFile +from django.conf import settings +import os @@ -53,6 +58,19 @@ def get_average_rating(self,list_values,key): return self.sum_values/len(list_values) +class DownloadTheme(APIView): + """download theme view + """ + permission_classes = (AllowAny,) + + def get(self,*args,**kwargs): + theme = Theme.objects.get(id=kwargs.get('theme_id')) + file = str(theme.file) + file.replace(" ","%20") + return Response({'download': file}) + + + diff --git a/market/settings.py b/market/settings.py index 80deed8..d2d9bea 100644 --- a/market/settings.py +++ b/market/settings.py @@ -9,7 +9,7 @@ # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ["*"] # Application definition diff --git a/themes/models.py b/themes/models.py index e308705..2c20cfe 100644 --- a/themes/models.py +++ b/themes/models.py @@ -9,6 +9,9 @@ def thumbnail_upload_path(instance, filename): def screenshot_upload_path(instance, filename): return f'images/{instance.theme.id}/screenshot/{filename}' +def theme_file_upload_path(instance, filename): + return f'download/{instance.id}/{instance.name}/{filename}' + class UserDownloadLog(models.Model): """user download log @@ -49,12 +52,13 @@ class Theme(models.Model): topic = models.ForeignKey('themes.Topic', on_delete=models.CASCADE, blank=True) labels = models.ManyToManyField('themes.Label', blank=True) license = models.ForeignKey('themes.License', on_delete=models.CASCADE, blank=True, null=True) + file = models.FileField(upload_to=theme_file_upload_path, null=True) release_date = models.DateField(auto_now=False,auto_now_add=False, blank=True) date_modified = models.DateField(auto_now=True) def __str__(self): - return f'{self.name, self.price, self.rating, self.version,}' + return f'{self.name, self.price, self.rating, self.version, self.file}' class Review(models.Model): diff --git a/themes/views.py b/themes/views.py index 42e09b5..fb1818f 100644 --- a/themes/views.py +++ b/themes/views.py @@ -1,11 +1,14 @@ from django.shortcuts import render +from django.conf import settings from django.core import serializers -from rest_framework.views import APIView +from django.views.generic import View from .models import (Theme, Thumbnail, Screenshot, Review, Browser, Category, Topic, Label, License) from .serializers import (ThemeDetailSerializer, ThumbnailSerializer, CategorySerializer, TopicSerializer, LicenseSerializer) +from rest_framework.views import APIView from rest_framework.permissions import AllowAny from rest_framework.response import Response - +from io import StringIO +from zipfile import ZipFile class ThemeFeed(APIView): """themes home @@ -111,3 +114,5 @@ def get(self,*args,**kwargs): category = Category.objects.all().values('category') return Response({'category': list(category)}, status=200) + + From 07420767b069bb1de28edc7b386cbbe354b85cd1 Mon Sep 17 00:00:00 2001 From: Miguel Dorado Date: Tue, 12 Feb 2019 11:21:28 +0800 Subject: [PATCH 05/17] can now change license type --- .../app/commons/services/cart/cart.service.ts | 17 ++++++++++ .../app/components/cart/cart.component.html | 32 +++++++++++++++++-- .../src/app/components/cart/cart.component.ts | 17 ++++++++++ themes/models.py | 2 +- themes/urls.py | 1 + themes/views.py | 15 +++++++++ 6 files changed, 81 insertions(+), 3 deletions(-) diff --git a/assets/src/app/commons/services/cart/cart.service.ts b/assets/src/app/commons/services/cart/cart.service.ts index 126347e..19f6b9a 100644 --- a/assets/src/app/commons/services/cart/cart.service.ts +++ b/assets/src/app/commons/services/cart/cart.service.ts @@ -8,6 +8,7 @@ export class CartService { httpHeaders = new HttpHeaders({'Content-type':'application/json'}); domain_url = '192.168.2.30'; + edit; constructor( private http: HttpClient) { } @@ -42,4 +43,20 @@ export class CartService { ) } + + editLicenseService(id,license_id){ + this.edit = {'id': id, 'license_id': license_id} + return this.http.post('http://'+this.domain_url+':8000/home/theme/edit_license/', this.edit) + .toPromise() + .then( + response => { + return response; + } + ) + .catch( + error => { + return error; + } + ) + } } diff --git a/assets/src/app/components/cart/cart.component.html b/assets/src/app/components/cart/cart.component.html index 45cca5c..2209e5e 100644 --- a/assets/src/app/components/cart/cart.component.html +++ b/assets/src/app/components/cart/cart.component.html @@ -12,7 +12,7 @@

{{theme.name}}

License Type:

{{ theme.license.license }}

- Change + Change

Unit Price:

@@ -41,4 +41,32 @@

${{ theme.price }}

- \ No newline at end of file + + + diff --git a/assets/src/app/components/cart/cart.component.ts b/assets/src/app/components/cart/cart.component.ts index 0985d83..32eb596 100644 --- a/assets/src/app/components/cart/cart.component.ts +++ b/assets/src/app/components/cart/cart.component.ts @@ -14,6 +14,8 @@ export class CartComponent implements OnInit { discount; dis_price; domain_url = '192.168.2.30'; + category; + constructor( private cartService: CartService, private route: ActivatedRoute, @@ -67,6 +69,21 @@ export class CartComponent implements OnInit { ) } + changeLicense(event,theme_id,license_id){ + this.cartService.editLicenseService(theme_id,license_id) + .then( + response => { + this.themeCart(); + return response; + } + ) + .catch( + error => { + return error; + } + ) + } + } diff --git a/themes/models.py b/themes/models.py index 2c20cfe..4e9aabc 100644 --- a/themes/models.py +++ b/themes/models.py @@ -58,7 +58,7 @@ class Theme(models.Model): date_modified = models.DateField(auto_now=True) def __str__(self): - return f'{self.name, self.price, self.rating, self.version, self.file}' + return f'{self.name, self.price, self.rating, self.version, self.file, self.license}' class Review(models.Model): diff --git a/themes/urls.py b/themes/urls.py index 1873102..db6893c 100644 --- a/themes/urls.py +++ b/themes/urls.py @@ -6,4 +6,5 @@ path('theme/details//', views.ThemeNameFilter.as_view()), path('theme/cart//', views.ThemeCart.as_view()), path('theme/category/',views.CategoryView.as_view()), + path('theme/edit_license/', views.EditLicense.as_view()), ] \ No newline at end of file diff --git a/themes/views.py b/themes/views.py index fb1818f..cdce45a 100644 --- a/themes/views.py +++ b/themes/views.py @@ -96,11 +96,13 @@ def get(self,*args,**kwargs): category = Category.objects.get(id=theme.category_id) thumbnail = Thumbnail.objects.get(theme_id=theme.id) license = License.objects.get(id=theme.license_id) + licenses = License.objects.all().values('pk','license') theme_s = ThemeDetailSerializer(theme).data theme_s['thumbnail'] = ThumbnailSerializer(thumbnail).data theme_s['category'] = CategorySerializer(category).data theme_s['license'] = LicenseSerializer(license).data + theme_s['licenses'] = {'license': list(licenses)} return Response(theme_s, status=200) @@ -116,3 +118,16 @@ def get(self,*args,**kwargs): return Response({'category': list(category)}, status=200) +class EditLicense(APIView): + """change license type + """ + permission_classes = (AllowAny,) + + def post(self,request,*args,**kwargs): + theme = Theme.objects.get(id=request.data['id']) + license = License.objects.get(id=request.data['license_id']) + theme.license = license + theme.save() + return Response({'success': 'license changed'},status=200) + + From ff6c7e6dde33db868aa567575ef8aa4a4df50acd Mon Sep 17 00:00:00 2001 From: Miguel Dorado Date: Tue, 12 Feb 2019 11:27:10 +0800 Subject: [PATCH 06/17] pull remote changes --- assets/src/app/app.component.ts | 1 + themes/views.py | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/assets/src/app/app.component.ts b/assets/src/app/app.component.ts index 05d029f..04ec300 100644 --- a/assets/src/app/app.component.ts +++ b/assets/src/app/app.component.ts @@ -11,6 +11,7 @@ import { Title } from '@angular/platform-browser'; styleUrls: ['./app.component.css'], providers: [AuthService] }) + export class AppComponent implements OnInit { usersForm; errors; diff --git a/themes/views.py b/themes/views.py index cdce45a..4255899 100644 --- a/themes/views.py +++ b/themes/views.py @@ -7,8 +7,6 @@ from rest_framework.views import APIView from rest_framework.permissions import AllowAny from rest_framework.response import Response -from io import StringIO -from zipfile import ZipFile class ThemeFeed(APIView): """themes home @@ -103,7 +101,7 @@ def get(self,*args,**kwargs): theme_s['category'] = CategorySerializer(category).data theme_s['license'] = LicenseSerializer(license).data theme_s['licenses'] = {'license': list(licenses)} - + return Response(theme_s, status=200) From faf22f6d55f1833d9b46047a257eb02d6f76856c Mon Sep 17 00:00:00 2001 From: Miguel Dorado Date: Tue, 12 Feb 2019 14:37:14 +0800 Subject: [PATCH 07/17] fixed remember me issue --- users/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/users/views.py b/users/views.py index 355870e..d63ad2a 100644 --- a/users/views.py +++ b/users/views.py @@ -59,7 +59,7 @@ def post(self,request,*args,**kwargs): class RefreshToken(APIView): """refresh token """ - permission_classes = (IsAuthenticated,) + permission_classes = (AllowAny,) def get(self,request,*args,**kwargs): From 101b98902077f96886a2d78aa1355dff3c3c2afd Mon Sep 17 00:00:00 2001 From: Miguel Dorado Date: Wed, 13 Feb 2019 11:01:53 +0800 Subject: [PATCH 08/17] can now send subscribe message on gmail account users, email accounts that are subscribe to the market --- .../app/commons/services/home/home.service.ts | 16 ++ .../app/components/home/home.component.html | 7 +- .../src/app/components/home/home.component.ts | 31 ++- market/settings.py | 9 +- themes/admin.py | 194 ++++++++++-------- themes/models.py | 12 ++ themes/urls.py | 1 + themes/views.py | 36 +++- 8 files changed, 209 insertions(+), 97 deletions(-) diff --git a/assets/src/app/commons/services/home/home.service.ts b/assets/src/app/commons/services/home/home.service.ts index b32c43d..a15edb6 100644 --- a/assets/src/app/commons/services/home/home.service.ts +++ b/assets/src/app/commons/services/home/home.service.ts @@ -44,5 +44,21 @@ export class HomeService { ) } + subscribeService(data){ + console.log('clicked'); + return this.http.post("http://"+this.domain_url+":8000/home/theme/subscribe/", data) + .toPromise() + .then( + response => { + return response; + } + ) + .catch( + error => { + return error; + } + ) + } + } diff --git a/assets/src/app/components/home/home.component.html b/assets/src/app/components/home/home.component.html index 0310313..653e25e 100644 --- a/assets/src/app/components/home/home.component.html +++ b/assets/src/app/components/home/home.component.html @@ -136,12 +136,15 @@
{{ theme.name }}

Be the first to know!

Get the updates about new products.

+
+
\ No newline at end of file diff --git a/assets/src/app/components/home/home.component.ts b/assets/src/app/components/home/home.component.ts index 1c7c293..1103b19 100644 --- a/assets/src/app/components/home/home.component.ts +++ b/assets/src/app/components/home/home.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { HomeService } from '../../commons/services/home/home.service'; import { Title } from '@angular/platform-browser'; import { CategoryPipe } from '../../commons/pipes/category/category.pipe'; -import { FormBuilder, FormGroup } from '@angular/forms'; +import { FormBuilder, FormGroup, FormControl, Validators } from '@angular/forms'; const categories = ['Angular JS','E-Commerce','General','Bootstrap 4']; @@ -19,15 +19,24 @@ export class HomeComponent implements OnInit { searchCategory; domain_url = '192.168.2.30'; baseUrl = "http://"+this.domain_url+":8000/media/"; - + subscriber; constructor( private home: HomeService, - private title: Title) {} + private title: Title, + private fb: FormBuilder) {} ngOnInit() { this.getThemesHome(); this.title.setTitle('Home - Marketplace'); + this.subscriber = this.fb.group({ + email : new FormControl('', Validators.required) + }); + + } + + get email(){ + return this.subscriber.email; } getThemesHome(){ @@ -59,4 +68,20 @@ export class HomeComponent implements OnInit { return `${choice}`; } + subscribeMarket(){ + console.log('clicked'); + this.home.subscribeService(this.subscriber.value) + .then( + response => { + console.log(response); + return response; + } + ) + .catch( + error => { + return error; + } + ) + } + } diff --git a/market/settings.py b/market/settings.py index d2d9bea..6ad73c8 100644 --- a/market/settings.py +++ b/market/settings.py @@ -159,7 +159,14 @@ os.path.join(BASE_DIR, 'assets/'), ] -EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' +EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' +EMAIL_HOST = 'smtp.gmail.com' +EMAIL_PORT = 587 +EMAIL_HOST_USER = 'bambolino35@gmail.com' +EMAIL_HOST_PASSWORD = 'fqu8moex' +DEFAULT_FROM_EMAIL= EMAIL_HOST_USER +EMAIL_USE_TLS = True +EMAIL_USE_SSL = False # Allow any settings to be defined in local_settings.py which should be # ignored in your version control system allowing for settings to be diff --git a/themes/admin.py b/themes/admin.py index 4275afc..bfd90ed 100644 --- a/themes/admin.py +++ b/themes/admin.py @@ -1,136 +1,149 @@ from django.contrib import admin from django.contrib.auth.admin import UserAdmin -from .models import ( UserDownloadLog, Theme, Review, Thumbnail, Screenshot, Browser, Category, Topic, Label, License) +from .models import ( + UserDownloadLog, Theme, Review, Thumbnail, Screenshot, Browser, Category, Topic, Label, License, Subscriber) class UserDownloadLogAdmin(admin.ModelAdmin): - """user download log admin - """ - model = UserDownloadLog + """user download log admin + """ + model = UserDownloadLog - list_display = ( - 'user', - 'theme', - 'download_times', - 'date_created', - 'date_modified', - ) + list_display = ( + 'user', + 'theme', + 'download_times', + 'date_created', + 'date_modified', + ) class ThemeAdmin(admin.ModelAdmin): - """themes admin - """ - model = Theme + """themes admin + """ + model = Theme - list_display = ( - 'name', - 'description', - 'rating', - 'price', - 'discount', - 'version', - ) + list_display = ( + 'name', + 'description', + 'rating', + 'price', + 'discount', + 'version', + ) class ReviewAdmin(admin.ModelAdmin): - """review admin - """ - model = Review + """review admin + """ + model = Review - list_display = ( - 'user', - 'rating', - 'comment', - 'date_created', - 'date_modified', - ) + list_display = ( + 'user', + 'rating', + 'comment', + 'date_created', + 'date_modified', + ) class ThumbnailAdmin(admin.ModelAdmin): - """thumbnail admin - """ - model = Thumbnail + """thumbnail admin + """ + model = Thumbnail - list_display = ( - 'theme', - 'thumbnail', - 'date_created', - 'date_modified', - ) + list_display = ( + 'theme', + 'thumbnail', + 'date_created', + 'date_modified', + ) class ScreenshotAdmin(admin.ModelAdmin): - """screenshot admin - """ - model = Screenshot + """screenshot admin + """ + model = Screenshot - list_display = ( - 'theme', - 'image', - 'date_created', - 'date_modified', - ) + list_display = ( + 'theme', + 'image', + 'date_created', + 'date_modified', + ) class BrowserAdmin(admin.ModelAdmin): - """browsers admin - """ - model = Browser + """browsers admin + """ + model = Browser - list_display = ( - 'browser', - 'date_created', - 'date_modified', - ) + list_display = ( + 'browser', + 'date_created', + 'date_modified', + ) class CategoryAdmin(admin.ModelAdmin): - """category admin - """ - model = Category + """category admin + """ + model = Category - list_display = ( - 'category', - 'date_created', - 'date_modified', - ) + list_display = ( + 'category', + 'date_created', + 'date_modified', + ) class TopicAdmin(admin.ModelAdmin): - """topic admin - """ - model = Topic + """topic admin + """ + model = Topic - list_display = ( - 'topic', - 'date_created', - 'date_modified', - ) + list_display = ( + 'topic', + 'date_created', + 'date_modified', + ) class LabelAdmin(admin.ModelAdmin): - """label admin - """ - model = Label + """label admin + """ + model = Label - list_display = ( - 'label', - 'date_created', - 'date_modified', - ) + list_display = ( + 'label', + 'date_created', + 'date_modified', + ) class LicenseAdmin(admin.ModelAdmin): - """license admin - """ - model = License + """license admin + """ + model = License - list_display = ( - 'license', - 'date_created', - 'date_modified', - ) + list_display = ( + 'license', + 'date_created', + 'date_modified', + ) +class SubscriberAdmin(admin.ModelAdmin): + """subscribers admin + """ + + model = Subscriber + + list_display = ( + 'user', + 'date_created', + 'date_modified', + ) + admin.site.register(UserDownloadLog, UserDownloadLogAdmin) admin.site.register(Theme, ThemeAdmin) @@ -142,3 +155,4 @@ class LicenseAdmin(admin.ModelAdmin): admin.site.register(Topic, TopicAdmin) admin.site.register(Label, LabelAdmin) admin.site.register(License, LicenseAdmin) +admin.site.register(Subscriber, SubscriberAdmin) diff --git a/themes/models.py b/themes/models.py index 4e9aabc..8c208ae 100644 --- a/themes/models.py +++ b/themes/models.py @@ -162,5 +162,17 @@ def __str__(self): return f'{self.license,}' +class Subscriber(models.Model): + """subscribe + """ + user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) + + date_created = models.DateField(auto_now_add=True) + date_modified = models.DateField(auto_now=True) + + def __str__(self): + return f'{self.user.email}' + + diff --git a/themes/urls.py b/themes/urls.py index db6893c..ac3bc06 100644 --- a/themes/urls.py +++ b/themes/urls.py @@ -7,4 +7,5 @@ path('theme/cart//', views.ThemeCart.as_view()), path('theme/category/',views.CategoryView.as_view()), path('theme/edit_license/', views.EditLicense.as_view()), + path('theme/subscribe/', views.Subscribe.as_view()), ] \ No newline at end of file diff --git a/themes/views.py b/themes/views.py index 4255899..15c4f32 100644 --- a/themes/views.py +++ b/themes/views.py @@ -2,11 +2,13 @@ from django.conf import settings from django.core import serializers from django.views.generic import View -from .models import (Theme, Thumbnail, Screenshot, Review, Browser, Category, Topic, Label, License) +from .models import (Theme, Thumbnail, Screenshot, Review, Browser, Category, Topic, Label, License, Subscriber) +from users.models import User from .serializers import (ThemeDetailSerializer, ThumbnailSerializer, CategorySerializer, TopicSerializer, LicenseSerializer) from rest_framework.views import APIView from rest_framework.permissions import AllowAny from rest_framework.response import Response +from django.core.mail import send_mail class ThemeFeed(APIView): """themes home @@ -129,3 +131,35 @@ def post(self,request,*args,**kwargs): return Response({'success': 'license changed'},status=200) +class Subscribe(APIView): + """send email for users to be updated with the latest published themes + """ + permission_classes = (AllowAny,) + # send_subscribers = [] + + def post(self,request,*args,**kwargs): + user = User.objects.get(email=request.data['email']) + subscribe = Subscriber.objects.create(user=user) + # subscribers = Subscriber.objects.all().values('user__email') + + # """implement array and append emails for sending a message to each user + # """ + # for users in subscribers: + # self.send_subscribers.append(users['user__email']) + + import pdb; pdb.set_trace() + + send_mail('Subscribed user', + 'Thank you for subscribing on our theme market, we will send you emails for the latest templates', + settings.EMAIL_HOST_USER, + [subscribe.user.email], + fail_silently=False, + ) + + return Response({'success': 'You are now subscribed!'}, status=200) + + +# class SendEmailSubscriber(APIView): +# """send email to subscribed users + + From 2ded57297c3e9ad4d83541dfe785b269e6ac4a13 Mon Sep 17 00:00:00 2001 From: Miguel Dorado Date: Wed, 13 Feb 2019 12:23:36 +0800 Subject: [PATCH 09/17] added messages and error messags when subscribing, when a email is already subscribed or a user is not yet registered --- .../app/components/home/home.component.html | 7 ++-- .../src/app/components/home/home.component.ts | 3 +- themes/views.py | 32 +++++++++++-------- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/assets/src/app/components/home/home.component.html b/assets/src/app/components/home/home.component.html index 653e25e..7961365 100644 --- a/assets/src/app/components/home/home.component.html +++ b/assets/src/app/components/home/home.component.html @@ -136,14 +136,17 @@
{{ theme.name }}

Be the first to know!

Get the updates about new products.

+ +

{{ message }}

+
diff --git a/assets/src/app/components/home/home.component.ts b/assets/src/app/components/home/home.component.ts index 1103b19..14c9dff 100644 --- a/assets/src/app/components/home/home.component.ts +++ b/assets/src/app/components/home/home.component.ts @@ -20,6 +20,7 @@ export class HomeComponent implements OnInit { domain_url = '192.168.2.30'; baseUrl = "http://"+this.domain_url+":8000/media/"; subscriber; + message; constructor( private home: HomeService, @@ -73,7 +74,7 @@ export class HomeComponent implements OnInit { this.home.subscribeService(this.subscriber.value) .then( response => { - console.log(response); + this.message = response.message; return response; } ) diff --git a/themes/views.py b/themes/views.py index 15c4f32..199b3c6 100644 --- a/themes/views.py +++ b/themes/views.py @@ -135,20 +135,28 @@ class Subscribe(APIView): """send email for users to be updated with the latest published themes """ permission_classes = (AllowAny,) - # send_subscribers = [] def post(self,request,*args,**kwargs): - user = User.objects.get(email=request.data['email']) - subscribe = Subscriber.objects.create(user=user) - # subscribers = Subscriber.objects.all().values('user__email') - # """implement array and append emails for sending a message to each user - # """ - # for users in subscribers: - # self.send_subscribers.append(users['user__email']) + """check if user is registered to the marketplace + """ + try: + user = User.objects.get(email=request.data['email']) + except: + return Response({'message': 'Please register before subscribing to the market'}) - import pdb; pdb.set_trace() + """check if subscriber is already subscribed to the marketplace + """ + subscriber = Subscriber.objects.filter(user=user) + if subscriber.exists(): + return Response({'message': 'You are already subscribed!'}, status=200) + """add user as a subscriber + """ + subscribe = Subscriber.objects.create(user=user) + + """send email via Gmail only + """ send_mail('Subscribed user', 'Thank you for subscribing on our theme market, we will send you emails for the latest templates', settings.EMAIL_HOST_USER, @@ -156,10 +164,6 @@ def post(self,request,*args,**kwargs): fail_silently=False, ) - return Response({'success': 'You are now subscribed!'}, status=200) - - -# class SendEmailSubscriber(APIView): -# """send email to subscribed users + return Response({'message': 'You are now subscribed!'}, status=200) From 21a359fc16636a4c5d03e176882c335b38b1493f Mon Sep 17 00:00:00 2001 From: Miguel Dorado Date: Wed, 13 Feb 2019 13:45:21 +0800 Subject: [PATCH 10/17] added subscribe feature in the details page, can send an email to user email via Gmail --- .../services/details/details.service.ts | 15 ++++++++++ .../components/details/details.component.html | 9 ++++-- .../components/details/details.component.ts | 28 ++++++++++++++++++- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/assets/src/app/commons/services/details/details.service.ts b/assets/src/app/commons/services/details/details.service.ts index 341226f..b2efe96 100644 --- a/assets/src/app/commons/services/details/details.service.ts +++ b/assets/src/app/commons/services/details/details.service.ts @@ -40,4 +40,19 @@ export class DetailsService { } ); } + + subscribeService(data){ + return this.http.post("http://"+this.domain_url+":8000/home/theme/subscribe/",data) + .toPromise() + .then( + response => { + return response; + } + ) + .catch( + error => { + return error; + } + ) + } } diff --git a/assets/src/app/components/details/details.component.html b/assets/src/app/components/details/details.component.html index 16578e8..e6d9bbc 100644 --- a/assets/src/app/components/details/details.component.html +++ b/assets/src/app/components/details/details.component.html @@ -342,12 +342,17 @@

Reviews

Be the first to know!

Get the updates about new products.

+ +

{{ message }}

+
+
+
\ No newline at end of file diff --git a/assets/src/app/components/details/details.component.ts b/assets/src/app/components/details/details.component.ts index 204a13a..93377c4 100644 --- a/assets/src/app/components/details/details.component.ts +++ b/assets/src/app/components/details/details.component.ts @@ -1,6 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { DetailsService } from '../../commons/services/details/details.service'; + import { Title } from '@angular/platform-browser'; import { FormBuilder, FormGroup, FormControl, Validators } from '@angular/forms'; @@ -19,6 +20,8 @@ export class DetailsComponent implements OnInit { reviews; content; token; + subscribe; + message; domain_url = '192.168.2.30'; constructor( @@ -41,6 +44,10 @@ export class DetailsComponent implements OnInit { rating : new FormControl('') }); + this.subscribe = this.fb.group({ + email : new FormControl('', Validators.required), + }); + } get review(){ @@ -51,6 +58,10 @@ export class DetailsComponent implements OnInit { return this.review.get('rating'); } + get email(){ + return this.subscribe.get('email'); + } + // get details of the theme getThemeDetails(){ this.detailsService.getThemeDetailsService(this.theme_id) @@ -91,6 +102,7 @@ export class DetailsComponent implements OnInit { this.getThemeDetails(); this.review.reset(); this.currentRate =0 + return response; } ) .catch( @@ -100,6 +112,20 @@ export class DetailsComponent implements OnInit { ) } + // subscribe user (details page) + subscribeMarket(){ + this.detailsService.subscribeService(this.subscribe.value) + .then( + response => { + this.message = response.message; + return response; + } + ) + .catch( + error => { + return error; + } + ) + } - } From c89b817ebc1b65265801ac96852bdd1ed018a8de Mon Sep 17 00:00:00 2001 From: Miguel Dorado Date: Sun, 17 Feb 2019 12:37:26 +0800 Subject: [PATCH 11/17] added constant for domain url, user cannot see products and buy themes instead redirected to a login modal --- assets/src/app/app.component.html | 2 +- assets/src/app/app.component.ts | 8 ++--- .../app/commons/constants/global.constants.ts | 9 +++++ .../app/commons/services/auth/auth.service.ts | 10 +++--- .../app/commons/services/cart/cart.service.ts | 8 ++--- .../services/details/details.service.ts | 8 ++--- .../app/commons/services/home/home.service.ts | 14 ++++---- .../components/account/account.component.html | 1 - .../app/components/cart/cart.component.html | 4 +-- .../src/app/components/cart/cart.component.ts | 3 +- .../components/details/details.component.html | 4 +-- .../components/details/details.component.ts | 4 +-- .../app/components/home/home.component.html | 15 +++++++-- .../src/app/components/home/home.component.ts | 33 ++++++++++++++----- assets/src/style.css.map | 7 ---- themes/urls.py | 2 +- themes/views.py | 5 ++- 17 files changed, 85 insertions(+), 52 deletions(-) create mode 100644 assets/src/app/commons/constants/global.constants.ts delete mode 100644 assets/src/style.css.map diff --git a/assets/src/app/app.component.html b/assets/src/app/app.component.html index e5fe93c..f283604 100644 --- a/assets/src/app/app.component.html +++ b/assets/src/app/app.component.html @@ -36,6 +36,7 @@

-
diff --git a/assets/src/app/app.component.ts b/assets/src/app/app.component.ts index 04ec300..b7f5611 100644 --- a/assets/src/app/app.component.ts +++ b/assets/src/app/app.component.ts @@ -4,6 +4,7 @@ import { FormControl, FormBuilder, Validators } from '@angular/forms'; import { Router } from '@angular/router'; import { Location } from '@angular/common'; import { Title } from '@angular/platform-browser'; +import { domain_url } from './commons/constants/global.constants'; @Component({ selector: 'app-root', @@ -16,8 +17,7 @@ export class AppComponent implements OnInit { usersForm; errors; rememberMe:boolean = false; - domain_url = '192.168.2.30'; - forgetPasswordUrl = "http://"+this.domain_url+":8000/user/password_reset/"; + forgetPasswordUrl = "http://"+domain_url+":8000/user/password_reset/"; constructor( private authService: AuthService, @@ -35,8 +35,8 @@ export class AppComponent implements OnInit { } - get username(){ - return this.usersForm.get('username'); + get email(){ + return this.usersForm.get('email'); } get password(){ diff --git a/assets/src/app/commons/constants/global.constants.ts b/assets/src/app/commons/constants/global.constants.ts new file mode 100644 index 0000000..db3ddba --- /dev/null +++ b/assets/src/app/commons/constants/global.constants.ts @@ -0,0 +1,9 @@ + export const domain_url = 'localhost'; + + // home urls + export const home_theme = '/home/theme/'; + export const home_category = '/home/theme/category/'; + export const home_subscribe = '/home/theme/subscribe/'; + +// categories + export const categories = ['Angular JS','E-Commerce','General','Bootstrap 4']; \ No newline at end of file diff --git a/assets/src/app/commons/services/auth/auth.service.ts b/assets/src/app/commons/services/auth/auth.service.ts index efa38be..1cf6a04 100644 --- a/assets/src/app/commons/services/auth/auth.service.ts +++ b/assets/src/app/commons/services/auth/auth.service.ts @@ -1,5 +1,6 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; +import { domain_url } from '../../constants/global.constants'; @Injectable({ providedIn: 'root' @@ -8,14 +9,15 @@ export class AuthService { rememberMe:boolean; token; user; - domain_url = '192.168.2.30'; + constructor(private http: HttpClient) { } // Generate token upon login loginAuth(user,remember){ this.rememberMe = remember; this.user = user; - return this.http.post("http://"+this.domain_url+":8000/user/login/", user) + console.log("http://"+domain_url+":8000/user/login/"); + return this.http.post("http://"+domain_url+":8000/user/login/", user) .toPromise() .then( response => { @@ -32,7 +34,7 @@ export class AuthService { // Generate token upon register registerAuth(user){ - return this.http.post("http://"+this.domain_url+"/user/register/", user) + return this.http.post("http://"+domain_url+":8000/user/register/", user) .toPromise() .then( response => { @@ -45,7 +47,7 @@ export class AuthService { } refreshToken(user){ - return this.http.get("http://"+this.domain_url+"localhost:8000/user/refresh/", user) + return this.http.get("http://"+domain_url+":8000/user/refresh/", user) .toPromise() .then( response => { diff --git a/assets/src/app/commons/services/cart/cart.service.ts b/assets/src/app/commons/services/cart/cart.service.ts index 19f6b9a..2d76f24 100644 --- a/assets/src/app/commons/services/cart/cart.service.ts +++ b/assets/src/app/commons/services/cart/cart.service.ts @@ -1,5 +1,6 @@ import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { domain_url } from '../../constants/global.constants'; @Injectable({ providedIn: 'root' @@ -7,14 +8,13 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; export class CartService { httpHeaders = new HttpHeaders({'Content-type':'application/json'}); - domain_url = '192.168.2.30'; edit; constructor( private http: HttpClient) { } getThemeCart(id){ - return this.http.get('http://'+this.domain_url+':8000/home/theme/cart/'+id+'/', {headers: this.httpHeaders}) + return this.http.get('http://'+domain_url+':8000/home/theme/cart/'+id+'/', {headers: this.httpHeaders}) .toPromise() .then( response => { @@ -29,7 +29,7 @@ export class CartService { } buyThemeService(id){ - return this.http.get('http://'+this.domain_url+':8000/details/download/'+id+'/', {headers: this.httpHeaders}) + return this.http.get('http://'+domain_url+':8000/details/download/'+id+'/', {headers: this.httpHeaders}) .toPromise() .then( response => { @@ -46,7 +46,7 @@ export class CartService { editLicenseService(id,license_id){ this.edit = {'id': id, 'license_id': license_id} - return this.http.post('http://'+this.domain_url+':8000/home/theme/edit_license/', this.edit) + return this.http.post('http://'+domain_url+':8000/home/theme/edit_license/', this.edit) .toPromise() .then( response => { diff --git a/assets/src/app/commons/services/details/details.service.ts b/assets/src/app/commons/services/details/details.service.ts index b2efe96..c24e312 100644 --- a/assets/src/app/commons/services/details/details.service.ts +++ b/assets/src/app/commons/services/details/details.service.ts @@ -1,18 +1,18 @@ import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { domain_url } from '../../constants/global.constants'; @Injectable({ providedIn: 'root' }) export class DetailsService { - domain_url = '192.168.2.30'; httpHeaders = new HttpHeaders({'Content-type': 'application/json'}); constructor( private http: HttpClient) { } getThemeDetailsService(id){ - return this.http.get('http://'+this.domain_url+':8000/home/theme/details/'+id+'/', {headers: this.httpHeaders}) + return this.http.get('http://'+domain_url+':8000/home/theme/details/'+id+'/', {headers: this.httpHeaders}) .toPromise() .then( response =>{ @@ -27,7 +27,7 @@ export class DetailsService { } createReviewService(comment){ - return this.http.post("http://"+this.domain_url+":8000/details/createReview/",comment) + return this.http.post("http://"+domain_url+":8000/details/createReview/",comment) .toPromise() .then( response => { @@ -42,7 +42,7 @@ export class DetailsService { } subscribeService(data){ - return this.http.post("http://"+this.domain_url+":8000/home/theme/subscribe/",data) + return this.http.post("http://"+domain_url+":8000/home/theme/subscribe/",data) .toPromise() .then( response => { diff --git a/assets/src/app/commons/services/home/home.service.ts b/assets/src/app/commons/services/home/home.service.ts index a15edb6..19c7ef3 100644 --- a/assets/src/app/commons/services/home/home.service.ts +++ b/assets/src/app/commons/services/home/home.service.ts @@ -1,21 +1,19 @@ import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable } from 'rxjs'; +import { domain_url, home_theme, home_category, home_subscribe} from '../../constants/global.constants'; @Injectable({ providedIn: 'root' }) export class HomeService { - domain_url = '192.168.2.30'; httpHeaders = new HttpHeaders({'Content-type': 'application/json'}); public categories; - constructor(private http: HttpClient) { - this.categories = this.getCategory(); - } + constructor(private http: HttpClient) {} - getThemes(){ - return this.http.get("http://"+this.domain_url+":8000/home/theme/", {headers: this.httpHeaders}) + getThemes(auth){ + return this.http.get("http://"+domain_url+":8000"+home_theme+auth+"/", {headers: this.httpHeaders}) .toPromise() .then( response => { @@ -30,7 +28,7 @@ export class HomeService { } getCategory(){ - return this.http.get("http://"+this.domain_url+":8000/home/theme/category/", {headers: this.httpHeaders}) + return this.http.get("http://"+domain_url+":8000"+home_category, {headers: this.httpHeaders}) .toPromise() .then( response => { @@ -46,7 +44,7 @@ export class HomeService { subscribeService(data){ console.log('clicked'); - return this.http.post("http://"+this.domain_url+":8000/home/theme/subscribe/", data) + return this.http.post("http://"+domain_url+":8000"+home_subscribe, data) .toPromise() .then( response => { diff --git a/assets/src/app/components/account/account.component.html b/assets/src/app/components/account/account.component.html index 2ad48c1..0f7fbb8 100644 --- a/assets/src/app/components/account/account.component.html +++ b/assets/src/app/components/account/account.component.html @@ -67,7 +67,6 @@

- {{ registrationForm.value.success }}
diff --git a/assets/src/app/components/cart/cart.component.html b/assets/src/app/components/cart/cart.component.html index 2209e5e..8368118 100644 --- a/assets/src/app/components/cart/cart.component.html +++ b/assets/src/app/components/cart/cart.component.html @@ -2,7 +2,7 @@
- +
@@ -30,7 +30,7 @@

${{ theme.price }}

Payment:

- +
diff --git a/assets/src/app/components/home/home.component.ts b/assets/src/app/components/home/home.component.ts index 3693118..bca9fc8 100644 --- a/assets/src/app/components/home/home.component.ts +++ b/assets/src/app/components/home/home.component.ts @@ -18,12 +18,18 @@ export class HomeComponent implements OnInit { themes; category; searchCategory; +<<<<<<< HEAD baseUrl = "http://"+domain_url+":8000/media/"; subscriber; message; authenticate; authenticated; login; +======= + baseUrl = "http://localhost:8000/media/"; + demoUrl = "http://localhost:5000/themes/"; + +>>>>>>> feature/home-view-demo constructor( private home: HomeService, @@ -78,6 +84,7 @@ export class HomeComponent implements OnInit { return `${choice}`; } +<<<<<<< HEAD subscribeMarket(){ console.log('clicked'); this.home.subscribeService(this.subscriber.value) @@ -101,5 +108,13 @@ export class HomeComponent implements OnInit { } return true; } +======= + viewDemo(theme_id,theme_name){ + console.log(this.demoUrl+theme_id+'/'+theme_name+'/index.html'); + window.location.href = this.demoUrl+theme_id+'/'+theme_name+'/index.html'; + } + + +>>>>>>> feature/home-view-demo } From de43abc875db08b0f2df335d935d2745c8edf234 Mon Sep 17 00:00:00 2001 From: Miguel Dorado Date: Sun, 17 Feb 2019 14:44:24 +0800 Subject: [PATCH 14/17] resolved merge conflicts --- assets/src/app/components/home/home.component.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/assets/src/app/components/home/home.component.ts b/assets/src/app/components/home/home.component.ts index bca9fc8..67f8c85 100644 --- a/assets/src/app/components/home/home.component.ts +++ b/assets/src/app/components/home/home.component.ts @@ -18,18 +18,14 @@ export class HomeComponent implements OnInit { themes; category; searchCategory; -<<<<<<< HEAD baseUrl = "http://"+domain_url+":8000/media/"; subscriber; message; authenticate; authenticated; login; -======= - baseUrl = "http://localhost:8000/media/"; - demoUrl = "http://localhost:5000/themes/"; + demoUrl = "http://"+domain_url+":5000/themes/"; ->>>>>>> feature/home-view-demo constructor( private home: HomeService, @@ -84,7 +80,6 @@ export class HomeComponent implements OnInit { return `${choice}`; } -<<<<<<< HEAD subscribeMarket(){ console.log('clicked'); this.home.subscribeService(this.subscriber.value) @@ -108,13 +103,12 @@ export class HomeComponent implements OnInit { } return true; } -======= + viewDemo(theme_id,theme_name){ console.log(this.demoUrl+theme_id+'/'+theme_name+'/index.html'); window.location.href = this.demoUrl+theme_id+'/'+theme_name+'/index.html'; } ->>>>>>> feature/home-view-demo } From 011fcc72a5c157aff798cc28910c23c770d3e770 Mon Sep 17 00:00:00 2001 From: Miguel Dorado Date: Mon, 18 Feb 2019 00:23:41 +0800 Subject: [PATCH 15/17] added download model for counting download times in a theme --- assets/src/app/app.component.ts | 10 +- .../app/commons/constants/global.constants.ts | 5 +- .../app/commons/services/auth/auth.service.ts | 27 +- themes/models.py | 1 + users/backup.py | 361 ++++++++++++++++++ users/forms.py | 42 ++ users/views.py | 1 - users/views_backup.py | 99 +++++ 8 files changed, 520 insertions(+), 26 deletions(-) create mode 100644 users/backup.py create mode 100644 users/forms.py create mode 100644 users/views_backup.py diff --git a/assets/src/app/app.component.ts b/assets/src/app/app.component.ts index b7f5611..d6f7179 100644 --- a/assets/src/app/app.component.ts +++ b/assets/src/app/app.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, HostListener } from '@angular/core'; import { AuthService} from './commons/services/auth/auth.service'; import { FormControl, FormBuilder, Validators } from '@angular/forms'; import { Router } from '@angular/router'; @@ -14,6 +14,13 @@ import { domain_url } from './commons/constants/global.constants'; }) export class AppComponent implements OnInit { + @HostListener("window:beforeunload",["$event"]) + clearLocalStorage(event){ + if(JSON.parse(localStorage.getItem('remember')) === false){ + localStorage.clear(); + } + } + usersForm; errors; rememberMe:boolean = false; @@ -32,6 +39,7 @@ export class AppComponent implements OnInit { email : new FormControl('', [Validators.required, Validators.email]), password : new FormControl('', Validators.required) }); + console.log(JSON.parse(localStorage.getItem('remember'))); } diff --git a/assets/src/app/commons/constants/global.constants.ts b/assets/src/app/commons/constants/global.constants.ts index db3ddba..e31b3b3 100644 --- a/assets/src/app/commons/constants/global.constants.ts +++ b/assets/src/app/commons/constants/global.constants.ts @@ -6,4 +6,7 @@ export const home_subscribe = '/home/theme/subscribe/'; // categories - export const categories = ['Angular JS','E-Commerce','General','Bootstrap 4']; \ No newline at end of file + export const categories = ['Angular JS','E-Commerce','General','Bootstrap 4']; + + //user + export let user_object:any; \ No newline at end of file diff --git a/assets/src/app/commons/services/auth/auth.service.ts b/assets/src/app/commons/services/auth/auth.service.ts index 1cf6a04..54daab2 100644 --- a/assets/src/app/commons/services/auth/auth.service.ts +++ b/assets/src/app/commons/services/auth/auth.service.ts @@ -14,9 +14,8 @@ export class AuthService { // Generate token upon login loginAuth(user,remember){ - this.rememberMe = remember; - this.user = user; - console.log("http://"+domain_url+":8000/user/login/"); + localStorage['remember'] = JSON.stringify(remember); + localStorage['user'] = JSON.stringify(user); return this.http.post("http://"+domain_url+":8000/user/login/", user) .toPromise() .then( @@ -63,34 +62,16 @@ export class AuthService { setToken(token){ this.token = token; - if(this.rememberMe == true){ - localStorage['token'] = JSON.stringify(token); - } - else{ - sessionStorage['token'] = JSON.stringify(token); - } + localStorage['token'] = JSON.stringify(token); } getToken(){ - if(this.rememberMe == true){ let token = localStorage.getItem('token'); return JSON.parse(token); - } - this.getSessionToken(); - } - getSessionToken(){ - if(sessionStorage['token'] == null || - sessionStorage['token'] == undefined){ - return JSON.parse(null); - } - this.token = this.refreshToken(this.user); - sessionStorage['token'] = JSON.stringify(this.token); - - let token = sessionStorage.getItem('token'); - return JSON.parse(token); } + removeToken(){ localStorage.removeItem('token'); } diff --git a/themes/models.py b/themes/models.py index 8c208ae..bb2dec9 100644 --- a/themes/models.py +++ b/themes/models.py @@ -53,6 +53,7 @@ class Theme(models.Model): labels = models.ManyToManyField('themes.Label', blank=True) license = models.ForeignKey('themes.License', on_delete=models.CASCADE, blank=True, null=True) file = models.FileField(upload_to=theme_file_upload_path, null=True) + downloads = models.IntegerField(default=0) release_date = models.DateField(auto_now=False,auto_now_add=False, blank=True) date_modified = models.DateField(auto_now=True) diff --git a/users/backup.py b/users/backup.py new file mode 100644 index 0000000..6dc6168 --- /dev/null +++ b/users/backup.py @@ -0,0 +1,361 @@ +# users/views.py +from .models import User +from rest_framework import viewsets +from django.db import IntegrityError +from django.views.decorators.http import require_http_methods +from django.contrib.auth import authenticate, login +from .serializers import UserSerializer, LoginSerializer, RegisterSerializer +from .managers import UserManager +from rest_framework.exceptions import ValidationError +from rest_framework.views import APIView +from rest_framework.response import Response +from rest_framework import parsers, renderers +from rest_framework.permissions import IsAuthenticated, AllowAny +from rest_framework.authentication import TokenAuthentication +from rest_framework.authtoken.models import Token + +class UserViewSet(viewsets.ModelViewSet): + """user view set end point + """ + queryset = User.objects.all() + serializer_class = UserSerializer + permission_classes = IsAuthenticated + + +class Login(APIView): + """login + """ + serializer_class = LoginSerializer + permission_classes = (AllowAny,) + + def post(self,*args,**kwargs): + serializer = self.serializer_class( + data=self.request.data, request=self.request) + + serializer.is_valid(raise_exception=True) + token, _ = Token.objects.get_or_create(user=serializer.user) + + return Response({ + 'token': token.key, + }, status=200, headers={'Authorization': 'Token {}'.format(token.key)}) + + +class Register(APIView): + """register + """ + + serializer_class = RegisterSerializer + permission_classes = (AllowAny,) + + def post(self,request,*args,**kwargs): + serializer = self.serializer_class( + data=self.request.data) + + serializer.is_valid(raise_exception=True) + + user = serializer.save() + user.set_password(serializer.data['password']) + user.save() + + token, _ = Token.objects.get_or_create(user=user) + + return Response({ + 'token': token.key, + }, status=200, headers={'Authorization': 'Token {}'.format(token.key)}) + + +######################## + +# users/serializers.py +from rest_framework import serializers +from .models import User +from django.contrib.auth import authenticate, login +from rest_framework.authtoken.models import Token +from django.utils.translation import ugettext_lazy as _ + +class UserSerializer(serializers.ModelSerializer): + """user serializer + """ + class Meta: + model = User + + fields = ( + 'id', + 'email', + 'first_name', + 'last_name', + ) + +class LoginSerializer(serializers.Serializer): + """login serializer + """ + + user = None + + email = serializers.CharField(write_only=True) + password = serializers.CharField(write_only=True) + + def __init__(self, *args, **kwargs): + self.request = kwargs.pop('request', None) + return super(LoginSerializer, self).__init__(*args, **kwargs) + + def validate(self, data): + """ validate email credentials + """ + email, password = data.values() + + if not email or not password: + msg = _('Must include "email" and "password".') + raise serializers.ValidationError(msg, code='authorization') + + self.user = authenticate(request=self.request, + email=email, password=password) + + if not self.user: + msg = _('Invalid email or password') + raise serializers.ValidationError(msg, code='authorization') + + + return data + + +class RegisterSerializer(serializers.ModelSerializer): + """login serializer + """ + class Meta: + model = User + fields = ( + 'first_name', + 'last_name', + 'email', + 'password', + ) + + def validate(self,data): + first_name, last_name, email, password = data.values() + + if not first_name or not last_name or not email or not password: + msg = _('Must include all fields!') + raise serializersl.ValidationError(msg, code='authorization') + + self.user = authenticate( + email=email) + + if self.user: + msg = _('Email already existed!') + raise serializers.ValidationError(msg, code='authorization') + + return data + + def get_token(self): + if not self.user: + msg = _('Unable to login with provided credentials.') + raise serializers.ValidationError(msg, code="authorization") + + token, created = Token.objects.get_or_create(user=self.user) + return token + +################## + +# users/urls.py +from django.urls import path, include +from . import views +from rest_framework import routers +# from rest_framework.authtoken.views import ObtainAuthToken + +router = routers.DefaultRouter() +router.register(r'users', views.UserViewSet) +# router.register(r'register', views.RegisterViewSet) +# router.register(r'login', views.Login) + +urlpatterns = [ + path('', include(router.urls)), + path('login/', views.Login.as_view()), + path('register/', views.Register.as_view()), + path('auth/', include('rest_framework.urls', namespace='rest_framework')), + +] + + +#################################### +# ASSETS +# assets/src/app/commons/services/auth/authservice.ts +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; + +@Injectable({ + providedIn: 'root' +}) +export class AuthService { + + constructor(private http: HttpClient) { } + + // Generate token upon login + loginAuth(user){ + return this.http.post("http://localhost:8000/user/login/", user) + .toPromise() + .then( + response => { + this.setToken(response); + return response; + }) + .catch(error => { + return Promise.reject(error); + }); + } + + // Generate token upon register + registerAuth(user){ + return this.http.post("http://localhost:8000/user/register/", user) + .toPromise() + .then( + response => { + this.setToken(response); + return response; + }) + .catch(error => { + return Promise.reject(error); + }); + } + + logout(){ + + } + + setToken(token){ + localStorage['token'] = JSON.stringify(token); + } + + getToken(){ + let token = localStorage.getItem('token'); + return JSON.parse(token); + } + + removeToken(){ + localStorage.removeItem('token'); + } +} + +####################### +# assets/src/app/app.module.ts +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; +import { HttpClientModule,HTTP_INTERCEPTORS } from '@angular/common/http'; +import { RouterModule, Routes } from "@angular/router"; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { AppRoutingModule } from './app-routing.module'; + +//Service +import { TokenService } from './commons/services/interceptors/token.service'; + +//Modules +import { AccountModule } from './components/account/account.module'; + +//Components +import { AppComponent } from './app.component'; +import { HomeComponent } from './components/home/home.component'; +import { CartComponent } from './components/cart/cart.component'; +import { DetailsComponent } from './components/details/details.component'; +import { AccountComponent } from './components/account/account.component'; + +//Routes +const routes: Routes = [ + { path: '', component: HomeComponent }, + { path: 'details', component: DetailsComponent }, + { path: 'cart', component: CartComponent }, + { path: 'account', component: AccountComponent } +] + +@NgModule({ + declarations: [ + AppComponent, + HomeComponent, + CartComponent, + DetailsComponent, + AccountComponent, + + ], + imports: [ + AccountModule, + BrowserModule, + AppRoutingModule, + HttpClientModule, + FormsModule, + ReactiveFormsModule, + RouterModule.forRoot(routes, {onSameUrlNavigation: 'reload'}), + ], + providers: [ + { + provide: HTTP_INTERCEPTORS, + useClass: TokenService, + multi: true + } + ], + bootstrap: [AppComponent] +}) +export class AppModule { } + + +######################## +# assets/src/app/app.component.ts +import { Component } from '@angular/core'; +import { AuthService} from './commons/services/auth/auth.service'; +import { FormControl, FormBuilder, Validators } from '@angular/forms'; +import { Router } from '@angular/router'; +import { Location } from '@angular/common'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'], + providers: [AuthService] +}) +export class AppComponent { + title = 'angular'; + usersForm; + errors; + constructor( + private authService: AuthService, + private fb: FormBuilder, + private router: Router, + private location: Location + ){ + this.usersForm = this.fb.group({ + email : new FormControl('', [Validators.required, Validators.email]), + password : new FormControl('', Validators.required) + }); + } + + get username(){ + return this.usersForm.get('username'); + } + + get password(){ + return this.usersForm.get('password'); + } + + + login(){ + this.authService.loginAuth(this.usersForm.value) + .then( + response => { + console.log(response); + location.reload(); + this.router.navigate(['']); + }) + .catch( + error => { + this.errors = error.error.non_field_errors; + console.log(error); + return this.errors; + }); + + } + +} + + + + + + diff --git a/users/forms.py b/users/forms.py new file mode 100644 index 0000000..a4696c2 --- /dev/null +++ b/users/forms.py @@ -0,0 +1,42 @@ +from django import forms +from django.core.validators import RegexValidator +from django.core import validators +from django.shortcuts import render +from django.contrib.auth import authenticate +from .models import User + + +class RegisterForm(forms.ModelForm): + """register form + """ + + class Meta: + model = User + fields = ('first_name','last_name','email','password',) + + def clean_email(self): + email = User.objects.filter(email=self.cleaned_data['email']) + + if email.exists(): + raise forms.ValidationError('Invalid Email Address!') + return self.cleaned_data['email'] + + +class LoginForm(forms.ModelForm): + """login form + """ + + class Meta: + model = User + fields = ('email','password') + + def clean(self): + user = authenticate( + username = self.cleaned_data['email'], + password = self.cleaned_data['password'] + ) + + if user is not None: + return self.cleaned_data + raise forms.ValidationError('Invalid Email or Password') + diff --git a/users/views.py b/users/views.py index d11a5dd..e5f7017 100644 --- a/users/views.py +++ b/users/views.py @@ -63,7 +63,6 @@ class RefreshToken(APIView): permission_classes = (AllowAny,) def get(self,request,*args,**kwargs): - user = authenticate( username=request.data['email'], password=request.data['password'] diff --git a/users/views_backup.py b/users/views_backup.py new file mode 100644 index 0000000..e74450c --- /dev/null +++ b/users/views_backup.py @@ -0,0 +1,99 @@ +from django.shortcuts import render +from django.views.generic import (TemplateView,View) +from django.http import JsonResponse +from django.shortcuts import render,render_to_response +from django.template.loader import render_to_string +from django.contrib.auth import (authenticate,login) +from django.http import HttpResponse +from django.template import RequestContext +from .forms import (RegisterForm,LoginForm) +from .models import User + + +class Home(TemplateView): + """home + """ + + template_name = 'home/home.html' + + + def get(self,request,*args,**kwargs): + + context = { + 'log_forms': LoginForm() + } + + return render(request,self.template_name,context) + + +class Register(TemplateView): + """register + """ + + template_name = 'account/register.html' + + context = { + 'forms': RegisterForm(), + 'log_forms': LoginForm(), + } + + def get(self,request,*args,**kwargs): + return render(request,self.template_name,self.context) + + def post(self,request,*args,**kwargs): + + form = RegisterForm(request.POST) + + if form.is_valid(): + user = User.objects.create_user( + form.cleaned_data['email'], + form.cleaned_data['password'], + ) + + user.first_name = form.cleaned_data['first_name'] + user.last_name = form.cleaned_data['last_name'] + user.save() + + login(request,user) + + context = { + 'user': request.user, + 'logged_in': True, + } + + return render(request,'home/home.html',context) + + return JsonResponse(form.errors,safe=False) + + +class Login(TemplateView): + """login + """ + template_name = 'account/register.html' + + context = { + 'forms': RegisterForm(), + 'log_forms': LoginForm(), + } + + def post(self,request,*args,**kwargs): + form = LoginForm(request.POST) + + if form.is_valid(): + user = authenticate( + username=form.cleaned_data['email'], + password=form.cleaned_data['password'] + ) + + login(request,user) + + context = { + 'log_forms': LoginForm(), + 'user': request.user, + 'logged_in': True, + } + + import pdb; pdb.set_trace() + return render(request,'details/details.html', context) + + return JsonResponse(form.errors,safe=False) From e5f343ad03e049e6043403fc476998cb60e1d977 Mon Sep 17 00:00:00 2001 From: Miguel Dorado Date: Mon, 18 Feb 2019 10:14:06 +0800 Subject: [PATCH 16/17] can see how many downloads a theme has --- .../app/commons/services/cart/cart.service.ts | 15 +++ .../src/app/components/cart/cart.component.ts | 16 +++ .../components/details/details.component.html | 2 +- details/views.py | 97 ++++++++++--------- themes/views.py | 1 + 5 files changed, 83 insertions(+), 48 deletions(-) diff --git a/assets/src/app/commons/services/cart/cart.service.ts b/assets/src/app/commons/services/cart/cart.service.ts index 2d76f24..0657973 100644 --- a/assets/src/app/commons/services/cart/cart.service.ts +++ b/assets/src/app/commons/services/cart/cart.service.ts @@ -59,4 +59,19 @@ export class CartService { } ) } + + incrementDownloadService(id){ + return this.http.get('http://'+domain_url+':8000/details/download/'+id+'/') + .toPromise() + .then( + response => { + return response; + } + ) + .catch( + error => { + return error; + } + ) + } } diff --git a/assets/src/app/components/cart/cart.component.ts b/assets/src/app/components/cart/cart.component.ts index b55b38f..4f4803e 100644 --- a/assets/src/app/components/cart/cart.component.ts +++ b/assets/src/app/components/cart/cart.component.ts @@ -85,6 +85,22 @@ export class CartComponent implements OnInit { ) } + incrementDownload(id){ + console.log('clicked'); + this.cartService.incrementDownloadService(id) + .then( + response => { + console.log(response); + return response; + } + ) + .catch( + error => { + return error; + } + ) + } + } diff --git a/assets/src/app/components/details/details.component.html b/assets/src/app/components/details/details.component.html index dfc36d4..a02e49e 100644 --- a/assets/src/app/components/details/details.component.html +++ b/assets/src/app/components/details/details.component.html @@ -73,7 +73,7 @@

{{ theme.name }}

-

(20 Downloads)

+

({{ theme.downloads }} Downloads)

diff --git a/details/views.py b/details/views.py index f9cee80..a570a60 100644 --- a/details/views.py +++ b/details/views.py @@ -13,49 +13,48 @@ import os - class CreateReview(APIView): - """create a review on a post - """ - permission_classes = (AllowAny,) - sum_values = 0 - - def post(self,request,*args,**kwargs): - """ - """ - token = request.data.get('token') - - request.data['user'] = Token.objects.get(key=token).user_id - request.data['theme'] = request.data.get('theme_id') - - serializer = ReviewSerializer( - data=request.data) - - """save review after validation - """ - serializer.is_valid(raise_exception=True) - serializer.save() - - """get average rating of the theme between the ratings of the reviews - """ - theme_rating = Theme.objects.get(id=request.data.get('theme_id')) - reviews_rating = Review.objects.filter(theme_id=request.data.get('theme_id')).values('rating') - list_values = list(reviews_rating) - average_rating = self.get_average_rating(list_values,'rating') - - """update theme with new rating - """ - theme_rating.rating = int(average_rating) - theme_rating.save() - - return Response({'success': 'Review created!'}, status=200) - - - def get_average_rating(self,list_values,key): - - for rating in list_values: - self.sum_values += rating[key] - return self.sum_values/len(list_values) + """create a review on a post + """ + permission_classes = (AllowAny,) + sum_values = 0 + + def post(self,request,*args,**kwargs): + """ + """ + token = request.data.get('token') + + request.data['user'] = Token.objects.get(key=token).user_id + request.data['theme'] = request.data.get('theme_id') + + serializer = ReviewSerializer( + data=request.data) + + """save review after validation + """ + serializer.is_valid(raise_exception=True) + serializer.save() + + """get average rating of the theme between the ratings of the reviews + """ + theme_rating = Theme.objects.get(id=request.data.get('theme_id')) + reviews_rating = Review.objects.filter(theme_id=request.data.get('theme_id')).values('rating') + list_values = list(reviews_rating) + average_rating = self.get_average_rating(list_values,'rating') + + """update theme with new rating + """ + theme_rating.rating = int(average_rating) + theme_rating.save() + + return Response({'success': 'Review created!'}, status=200) + + + def get_average_rating(self,list_values,key): + + for rating in list_values: + self.sum_values += rating[key] + return self.sum_values/len(list_values) class DownloadTheme(APIView): @@ -64,10 +63,14 @@ class DownloadTheme(APIView): permission_classes = (AllowAny,) def get(self,*args,**kwargs): + """ + increment downloads for theme + """ theme = Theme.objects.get(id=kwargs.get('theme_id')) - file = str(theme.file) - file.replace(" ","%20") - return Response({'download': file}) + theme.downloads+=1 + theme.save() + + return Response({'increment': 'Theme has '+ theme['downloads']},status=200) @@ -75,7 +78,7 @@ def get(self,*args,**kwargs): - + - \ No newline at end of file + \ No newline at end of file diff --git a/themes/views.py b/themes/views.py index 931c6b2..2d22292 100644 --- a/themes/views.py +++ b/themes/views.py @@ -127,6 +127,7 @@ class EditLicense(APIView): permission_classes = (AllowAny,) def post(self,request,*args,**kwargs): + import pdb; pdb.set_trace() theme = Theme.objects.get(id=request.data['id']) license = License.objects.get(id=request.data['license_id']) theme.license = license From 5d349e5c5b708d716b852ab51b153675bf9395f4 Mon Sep 17 00:00:00 2001 From: Miguel Dorado Date: Mon, 18 Feb 2019 10:27:57 +0800 Subject: [PATCH 17/17] replaced open eye --- assets/src/assets/images/eye-open.svg | 68 +++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 10 deletions(-) diff --git a/assets/src/assets/images/eye-open.svg b/assets/src/assets/images/eye-open.svg index 2f83526..fbe72ed 100644 --- a/assets/src/assets/images/eye-open.svg +++ b/assets/src/assets/images/eye-open.svg @@ -1,10 +1,58 @@ - - - - - - eye - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +