From e97c9ec55de8b1a2ba8b97885c69c9dd8154eeec Mon Sep 17 00:00:00 2001 From: Miguel Dorado Date: Thu, 31 Jan 2019 11:10:52 +0800 Subject: [PATCH 1/3] added license model, put license dynamically on cart page --- .../app/components/cart/cart.component.html | 2 +- themes/admin.py | 16 +++++++++++++- themes/migrations/0020_license.py | 22 +++++++++++++++++++ themes/migrations/0021_theme_license.py | 19 ++++++++++++++++ themes/models.py | 13 +++++++++++ themes/views.py | 7 +++--- 6 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 themes/migrations/0020_license.py create mode 100644 themes/migrations/0021_theme_license.py diff --git a/assets/src/app/components/cart/cart.component.html b/assets/src/app/components/cart/cart.component.html index c0beac6..e398c47 100644 --- a/assets/src/app/components/cart/cart.component.html +++ b/assets/src/app/components/cart/cart.component.html @@ -11,7 +11,7 @@

{{theme.name}}

{{theme.description}}

License Type:

-

1 Standard License

+

{{ theme.license.license }}

Change
diff --git a/themes/admin.py b/themes/admin.py index bac5908..4275afc 100644 --- a/themes/admin.py +++ b/themes/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin from django.contrib.auth.admin import UserAdmin -from .models import ( UserDownloadLog, Theme, Review, Thumbnail, Screenshot, Browser, Category, Topic, Label) +from .models import ( UserDownloadLog, Theme, Review, Thumbnail, Screenshot, Browser, Category, Topic, Label, License) class UserDownloadLogAdmin(admin.ModelAdmin): @@ -119,6 +119,19 @@ class LabelAdmin(admin.ModelAdmin): ) +class LicenseAdmin(admin.ModelAdmin): + """license admin + """ + model = License + + list_display = ( + 'license', + 'date_created', + 'date_modified', + ) + + + admin.site.register(UserDownloadLog, UserDownloadLogAdmin) admin.site.register(Theme, ThemeAdmin) admin.site.register(Review, ReviewAdmin) @@ -128,3 +141,4 @@ class LabelAdmin(admin.ModelAdmin): admin.site.register(Category, CategoryAdmin) admin.site.register(Topic, TopicAdmin) admin.site.register(Label, LabelAdmin) +admin.site.register(License, LicenseAdmin) diff --git a/themes/migrations/0020_license.py b/themes/migrations/0020_license.py new file mode 100644 index 0000000..79c843e --- /dev/null +++ b/themes/migrations/0020_license.py @@ -0,0 +1,22 @@ +# Generated by Django 2.1.5 on 2019-01-31 02:12 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('themes', '0019_auto_20190108_0553'), + ] + + operations = [ + migrations.CreateModel( + name='License', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('license', models.CharField(max_length=100)), + ('date_created', models.DateField(auto_now_add=True)), + ('date_modified', models.DateField(auto_now=True)), + ], + ), + ] diff --git a/themes/migrations/0021_theme_license.py b/themes/migrations/0021_theme_license.py new file mode 100644 index 0000000..62df0c2 --- /dev/null +++ b/themes/migrations/0021_theme_license.py @@ -0,0 +1,19 @@ +# Generated by Django 2.1.5 on 2019-01-31 02:31 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('themes', '0020_license'), + ] + + operations = [ + migrations.AddField( + model_name='theme', + name='license', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='themes.License'), + ), + ] diff --git a/themes/models.py b/themes/models.py index 0f92374..e308705 100644 --- a/themes/models.py +++ b/themes/models.py @@ -48,6 +48,7 @@ class Theme(models.Model): category = models.ForeignKey('themes.Category', on_delete=models.CASCADE, blank=True) 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) release_date = models.DateField(auto_now=False,auto_now_add=False, blank=True) date_modified = models.DateField(auto_now=True) @@ -145,5 +146,17 @@ def __str__(self): return f'{self.label,}' +class License(models.Model): + """license + """ + license = models.CharField(max_length=100) + + date_created = models.DateField(auto_now_add=True) + date_modified = models.DateField(auto_now=True) + + def __str__(self): + return f'{self.license,}' + + diff --git a/themes/views.py b/themes/views.py index 0cf25cc..12f9522 100644 --- a/themes/views.py +++ b/themes/views.py @@ -1,8 +1,8 @@ from django.shortcuts import render from django.core import serializers from rest_framework.views import APIView -from .models import (Theme, Thumbnail, Screenshot, Review, Browser, Category, Topic, Label, ) -from .serializers import (ThemeDetailSerializer, ThumbnailSerializer, CategorySerializer, TopicSerializer,) +from .models import (Theme, Thumbnail, Screenshot, Review, Browser, Category, Topic, Label, License) +from .serializers import (ThemeDetailSerializer, ThumbnailSerializer, CategorySerializer, TopicSerializer, LicenseSerializer) from rest_framework.permissions import AllowAny from rest_framework.response import Response from itertools import chain @@ -72,11 +72,12 @@ def get(self,*args,**kwargs): theme = Theme.objects.get(id=kwargs['id']) category = Category.objects.get(id=theme.category_id) thumbnail = Thumbnail.objects.get(theme_id=theme.id) + license = License.objects.get(id=theme.license_id) theme_s = ThemeDetailSerializer(theme).data theme_s['thumbnail'] = ThumbnailSerializer(thumbnail).data theme_s['category'] = CategorySerializer(category).data - + theme_s['license'] = LicenseSerializer(license).data return Response(theme_s, status=200) From 91ade5879a40d2bb00e7da6acd704e3f30831d68 Mon Sep 17 00:00:00 2001 From: Miguel Dorado Date: Thu, 31 Jan 2019 11:19:34 +0800 Subject: [PATCH 2/3] removed pdb in register --- themes/views.py | 2 -- users/views.py | 1 - 2 files changed, 3 deletions(-) diff --git a/themes/views.py b/themes/views.py index 12f9522..4fdc804 100644 --- a/themes/views.py +++ b/themes/views.py @@ -9,8 +9,6 @@ import json - - class ThemeFeed(APIView): """themes home """ diff --git a/users/views.py b/users/views.py index 302f992..9e9146c 100644 --- a/users/views.py +++ b/users/views.py @@ -40,7 +40,6 @@ class Register(APIView): permission_classes = (AllowAny,) def post(self,request,*args,**kwargs): - import pdb; pdb.set_trace() serializer = self.serializer_class( data=self.request.data) From 3cd172a1499dfbd6c8bbce1eeca988311448279e Mon Sep 17 00:00:00 2001 From: Miguel Dorado Date: Tue, 5 Feb 2019 09:48:56 +0800 Subject: [PATCH 3/3] search filter functional, autocomplete search implemented --- assets/package-lock.json | 51 +++++++++++++++++-- assets/package.json | 9 +++- assets/src/app/app.module.ts | 16 ++++-- .../pipes/category/category.pipe.spec.ts | 8 +++ .../commons/pipes/category/category.pipe.ts | 18 +++++++ .../app/commons/services/home/home.service.ts | 22 +++++++- .../app/components/home/home.component.html | 34 ++++++++++--- .../src/app/components/home/home.component.ts | 38 +++++++++++--- assets/src/assets/js/main_script.js | 12 ++--- themes/urls.py | 4 +- themes/views.py | 20 ++++++-- 11 files changed, 194 insertions(+), 38 deletions(-) create mode 100644 assets/src/app/commons/pipes/category/category.pipe.spec.ts create mode 100644 assets/src/app/commons/pipes/category/category.pipe.ts diff --git a/assets/package-lock.json b/assets/package-lock.json index 9174aff..449bf0b 100644 --- a/assets/package-lock.json +++ b/assets/package-lock.json @@ -1,6 +1,6 @@ { - "name": "swiftkind", - "version": "2.0.0", + "name": "angular", + "version": "0.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -9,6 +9,22 @@ "resolved": "https://registry.npmjs.org/almond/-/almond-0.3.3.tgz", "integrity": "sha1-oOfJWsdiTWQXtElLHmi/9pMWiiA=" }, + "angular-text-input-autocomplete": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/angular-text-input-autocomplete/-/angular-text-input-autocomplete-0.3.0.tgz", + "integrity": "sha512-0oZBc1YhPalu7gOHqW8nEnkslnR+hcpnB79qV63opZbga1c0pfL4/MeKjVxW6SBauLCFAVoO1Mka0kwT80DSyw==", + "requires": { + "textarea-caret": "^3.1.0", + "tslib": "^1.9.0" + }, + "dependencies": { + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" + } + } + }, "animate.css": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/animate.css/-/animate.css-3.7.0.tgz", @@ -34,6 +50,26 @@ "resolved": "https://registry.npmjs.org/jquery-mousewheel/-/jquery-mousewheel-3.1.13.tgz", "integrity": "sha1-BvAzXxbjU6aV5yBr9QUDy1I6buU=" }, + "keyboardevent-key-polyfill": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/keyboardevent-key-polyfill/-/keyboardevent-key-polyfill-1.1.0.tgz", + "integrity": "sha1-ijGdjkWhMXL8pWKGNy+QwdTHAUw=" + }, + "ng-select2": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/ng-select2/-/ng-select2-1.0.8.tgz", + "integrity": "sha512-cMonV4RMKmJGw4MSuTJumLDDaZao3r8slGu53GlrdyOSAEMsrjuHKeWQxMlcBFTAqiSwImugYPulfZSXPmlO2w==", + "requires": { + "tslib": "^1.9.0" + }, + "dependencies": { + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" + } + } + }, "popper.js": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.1.tgz", @@ -49,16 +85,21 @@ "resolved": "https://registry.npmjs.org/select2/-/select2-4.0.6-rc.1.tgz", "integrity": "sha1-qmwwOKfw8ukf+t448KIcFeGBMnY=", "requires": { - "almond": "0.3.3", - "jquery-mousewheel": "3.1.13" + "almond": "~0.3.1", + "jquery-mousewheel": "~3.1.13" } }, + "textarea-caret": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/textarea-caret/-/textarea-caret-3.1.0.tgz", + "integrity": "sha512-cXAvzO9pP5CGa6NKx0WYHl+8CHKZs8byMkt3PCJBCmq2a34YA9pO1NrQET5pzeqnBjBdToF5No4rrmkDUgQC2Q==" + }, "wowjs": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/wowjs/-/wowjs-1.1.3.tgz", "integrity": "sha1-RA/Bu0x+iWhA7keXIpaitZB1rL0=", "requires": { - "animate.css": "3.7.0" + "animate.css": "^3.7.0" }, "dependencies": { "animate.css": { diff --git a/assets/package.json b/assets/package.json index f9bef8d..cd4cf6e 100644 --- a/assets/package.json +++ b/assets/package.json @@ -12,20 +12,27 @@ "private": true, "dependencies": { "@angular/animations": "~7.1.0", + "@angular/cdk": "~7.2.2", "@angular/common": "~7.1.0", "@angular/compiler": "~7.1.0", "@angular/core": "^7.0.0", "@angular/forms": "~7.1.0", + "@angular/material": "~7.2.2", "@angular/platform-browser": "~7.1.0", "@angular/platform-browser-dynamic": "~7.1.0", "@angular/router": "~7.1.0", + "@auth0/angular-jwt": "^2.1.0", "angular-jwt": "^0.1.10", + "angular-text-input-autocomplete": "^0.3.0", "angular2-jwt": "^0.2.3", "animate.css": "^3.7.0", "bootstrap": "^4.0.0", "core-js": "^2.5.4", "ionicons": "^2.0.1", "jquery": "^3.3.1", + "keyboardevent-key-polyfill": "^1.1.0", + "ng-select2": "^1.0.8", + "ng2-select2": "^1.0.0-beta.11", "popper.js": "^1.14.1", "retinajs": "^2.1.3", "rxjs": "~6.3.3", @@ -55,4 +62,4 @@ "tslint": "~5.11.0", "typescript": "~3.1.6" } -} +} \ No newline at end of file diff --git a/assets/src/app/app.module.ts b/assets/src/app/app.module.ts index 465bfab..1eda7f3 100644 --- a/assets/src/app/app.module.ts +++ b/assets/src/app/app.module.ts @@ -1,11 +1,13 @@ import { BrowserModule } from '@angular/platform-browser'; -import { NgModule } from '@angular/core'; +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } 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'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations' -// import { MatGridModule } from '@angular/material'; +import { Select2Module } from 'ng2-select2'; +import { polyfill } from 'keyboardevent-key-polyfill'; +import { TextInputAutocompleteModule } from 'angular-text-input-autocomplete'; //Service import { TokenService } from './commons/services/interceptors/token.service'; @@ -20,6 +22,9 @@ import { CartComponent } from './components/cart/cart.component'; import { DetailsComponent } from './components/details/details.component'; import { AccountComponent } from './components/account/account.component'; +//Pipes +import { CategoryPipe } from './commons/pipes/category/category.pipe'; + //Routes const routes: Routes = [ { path: '', component: HomeComponent }, @@ -28,6 +33,8 @@ const routes: Routes = [ { path: 'account', component: AccountComponent } ] +polyfill(); + @NgModule({ declarations: [ AppComponent, @@ -35,6 +42,7 @@ const routes: Routes = [ CartComponent, DetailsComponent, AccountComponent, + CategoryPipe, ], imports: [ @@ -44,6 +52,7 @@ const routes: Routes = [ HttpClientModule, FormsModule, ReactiveFormsModule, + TextInputAutocompleteModule, RouterModule.forRoot(routes, {onSameUrlNavigation: 'reload'}), ], providers: [ @@ -53,6 +62,7 @@ const routes: Routes = [ multi: true } ], - bootstrap: [AppComponent] + bootstrap: [AppComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA] }) export class AppModule { } \ No newline at end of file diff --git a/assets/src/app/commons/pipes/category/category.pipe.spec.ts b/assets/src/app/commons/pipes/category/category.pipe.spec.ts new file mode 100644 index 0000000..45b4d74 --- /dev/null +++ b/assets/src/app/commons/pipes/category/category.pipe.spec.ts @@ -0,0 +1,8 @@ +import { CategoryPipe } from './category.pipe'; + +describe('CategoryPipe', () => { + it('create an instance', () => { + const pipe = new CategoryPipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/assets/src/app/commons/pipes/category/category.pipe.ts b/assets/src/app/commons/pipes/category/category.pipe.ts new file mode 100644 index 0000000..10ce382 --- /dev/null +++ b/assets/src/app/commons/pipes/category/category.pipe.ts @@ -0,0 +1,18 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'category' +}) +export class CategoryPipe implements PipeTransform { + + transform(category:any, args?: any): any { + if(args === undefined) return category; + + return category.filter( + cat => { + return cat.category__category.toLowerCase().includes(args.toLowerCase()); + } + ) + } + +} diff --git a/assets/src/app/commons/services/home/home.service.ts b/assets/src/app/commons/services/home/home.service.ts index ee2bccc..d9b62c2 100644 --- a/assets/src/app/commons/services/home/home.service.ts +++ b/assets/src/app/commons/services/home/home.service.ts @@ -1,5 +1,6 @@ import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' @@ -7,7 +8,10 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; export class HomeService { httpHeaders = new HttpHeaders({'Content-type': 'application/json'}); - constructor(private http: HttpClient) { } + public categories; + constructor(private http: HttpClient) { + this.categories = this.getCategory(); + } getThemes(){ return this.http.get("http://localhost:8000/home/theme/", {headers: this.httpHeaders}) @@ -24,4 +28,20 @@ export class HomeService { ) } + getCategory(){ + return this.http.get("http://localhost:8000/home/theme/category/", {headers: this.httpHeaders}) + .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 5968ea6..0310313 100644 --- a/assets/src/app/components/home/home.component.html +++ b/assets/src/app/components/home/home.component.html @@ -15,21 +15,41 @@

We created themes so everyone can finish projects on time ship
- + + + + + +
+
+

- +
- +
diff --git a/assets/src/app/components/home/home.component.ts b/assets/src/app/components/home/home.component.ts index 2078647..f37aaa3 100644 --- a/assets/src/app/components/home/home.component.ts +++ b/assets/src/app/components/home/home.component.ts @@ -1,40 +1,66 @@ 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'; + +const categories = ['Angular JS','E-Commerce','General','Bootstrap 4']; @Component({ selector: 'app-home', templateUrl: './home.component.html', - styleUrls: ['./home.component.css'] + styleUrls: ['./home.component.css'], + providers: [CategoryPipe,HomeService] + }) export class HomeComponent implements OnInit { themes; + category; + categories + searchCategory; + promise; baseUrl = "http://localhost:8000/media/"; + + constructor( private home: HomeService, - private title: Title) { - } + private title: Title, + private fb: FormBuilder) {} ngOnInit() { this.getThemesHome(); this.title.setTitle('Home - Marketplace'); + console.log(this.home.categories); } - + getThemesHome(){ this.home.getThemes() .then( response => { this.themes = response.data; - console.log(this.themes); + this.category = response.category return response; } ) .catch( error => { - console.log(error); return error; } ) } + findCategory(search: string){ + return categories.filter( + category => { + console.log(category); + return category.toLowerCase().includes(search.toLowerCase()); + } + + ); + } + + getChoice(choice: string){ + return `${choice}`; + } + } diff --git a/assets/src/assets/js/main_script.js b/assets/src/assets/js/main_script.js index f8387a0..988add8 100644 --- a/assets/src/assets/js/main_script.js +++ b/assets/src/assets/js/main_script.js @@ -1,7 +1,8 @@ $(document).ready(function() { - $('.multi-select').select2({ - placeholder: 'Search for names, categories or technologies' - }); + $('.multi-select').select2({ + placeholder: 'Search for categories' + }); + new WOW().init(); //unmasking the password @@ -9,11 +10,6 @@ $(document).ready(function() { $('.pw-masking').toggleClass('masked'); }); - // $('#pw-toggle-register').on('click', function() { - // console.log('clicked'); - // $('.pw-masking').toggleClass('masked'); - // }); - //toggling tooltips for passwords var inputMask = $('.input-pw'); inputMask.on('focus',function() { diff --git a/themes/urls.py b/themes/urls.py index 340a2f6..1873102 100644 --- a/themes/urls.py +++ b/themes/urls.py @@ -1,11 +1,9 @@ from django.urls import path, include from . import views -from rest_framework import routers - urlpatterns = [ path('theme/', views.ThemeFeed.as_view()), path('theme/details//', views.ThemeNameFilter.as_view()), path('theme/cart//', views.ThemeCart.as_view()), - + path('theme/category/',views.CategoryView.as_view()), ] \ No newline at end of file diff --git a/themes/views.py b/themes/views.py index 4fdc804..76dedfc 100644 --- a/themes/views.py +++ b/themes/views.py @@ -16,14 +16,16 @@ class ThemeFeed(APIView): permission_classes = (AllowAny,) def get(self,*args,**kwargs): - thumbnail = Thumbnail.objects.all() - + thumbnail = Thumbnail.objects.all().values() + category = Category.objects.all().values() + data = self.queryset.filter( id__in=thumbnail.values('theme_id') - ).values('id','name','rating','price','thumbnail__thumbnail') + ).values('id','name','rating','price','thumbnail__thumbnail','category__category') return Response({ 'data': list(data), + 'category': list(category), }, status=200) @@ -76,6 +78,16 @@ def get(self,*args,**kwargs): theme_s['thumbnail'] = ThumbnailSerializer(thumbnail).data theme_s['category'] = CategorySerializer(category).data theme_s['license'] = LicenseSerializer(license).data - + return Response(theme_s, status=200) + +class CategoryView(APIView): + """category + """ + permission_classes = (AllowAny,) + + def get(self,*args,**kwargs): + category = Category.objects.all().values('category') + + return Response({'category': list(category)}, status=200)