From 2f4f2d8bd105c9f92d49d8d4fb867cc3c5fbd3c4 Mon Sep 17 00:00:00 2001 From: Miguel Dorado Date: Mon, 11 Feb 2019 09:50:52 +0800 Subject: [PATCH 1/9] 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 2/9] 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 3/9] 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 4/9] 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 5/9] 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 6/9] 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 101b98902077f96886a2d78aa1355dff3c3c2afd Mon Sep 17 00:00:00 2001 From: Miguel Dorado Date: Wed, 13 Feb 2019 11:01:53 +0800 Subject: [PATCH 7/9] 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 8/9] 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 9/9] 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; + } + ) + } - }