diff --git a/.gitignore b/.gitignore index 9006ab5..e075ae2 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ static/ __pycache__/ env/ node_modules/ +themes/ +demo/ \ 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..05d029f 100644 --- a/assets/src/app/app.component.ts +++ b/assets/src/app/app.component.ts @@ -15,6 +15,8 @@ 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/"; 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 @@
- +
@@ -28,12 +28,14 @@

${{ theme.price }}

Payment:

-
+
- + + +
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 1b91af0..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 @@ -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/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..a589a25 --- /dev/null +++ b/templates/registration/password_reset_confirm.html @@ -0,0 +1,46 @@ +{% extends 'base.html' %} +{% load widget_tweaks %} +{% 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|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%} +

{% 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_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_form.html b/templates/registration/password_reset_form.html new file mode 100644 index 0000000..4028578 --- /dev/null +++ b/templates/registration/password_reset_form.html @@ -0,0 +1,35 @@ +{% 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/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 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) + + 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..c3cf6ab 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