diff --git a/trademark/__init__.py b/trademark/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/trademark/apps.py b/trademark/apps.py new file mode 100644 index 0000000..b22551e --- /dev/null +++ b/trademark/apps.py @@ -0,0 +1,8 @@ +#-*- coding: utf-8 -*- +from django.apps import AppConfig + + +class TrademarkConfig(AppConfig): + name = 'trademark' + verbose_name = "trademark" + \ No newline at end of file diff --git a/trademark/cms_app.py b/trademark/cms_app.py new file mode 100644 index 0000000..9cb4427 --- /dev/null +++ b/trademark/cms_app.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +from aldryn_apphooks_config.app_base import CMSConfigApp +from cms.apphook_pool import apphook_pool +from django.utils.translation import ugettext_lazy as _ + +from .models import TrademarkConfig + + +class TrademarkApp(CMSConfigApp): + app_config = TrademarkConfig + name = _('Trademark') + urls = ['trademark.urls'] + app_name = 'trademark' + +apphook_pool.register(TrademarkApp) diff --git a/trademark/cms_appconfig.py b/trademark/cms_appconfig.py new file mode 100644 index 0000000..fdb112f --- /dev/null +++ b/trademark/cms_appconfig.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- + +from __future__ import unicode_literals + +from django import forms +from django.conf import settings +from django.db import models +from django.utils.translation import ugettext_lazy as _ + +from aldryn_apphooks_config.utils import setup_config +from aldryn_apphooks_config.models import AppHookConfig +from app_data import AppDataForm +from parler.models import TranslatableModel +from parler.models import TranslatedFields + +from cms.models.fields import PlaceholderField + + +class TrademarkConfig(TranslatableModel, AppHookConfig): + """Adds some translatable, per-app-instance fields.""" + translations = TranslatedFields( + app_title=models.CharField(_('application title'), max_length=234), + ) + + # search_PAGINATE_BY + paginate_by = models.PositiveIntegerField( + _('Paginate size'), + blank=False, + default=5, + help_text=_('When paginating list views, how many articles per page?'), + ) + + placeholder_base_top = PlaceholderField( + 'trademark_search_base_top', + related_name='search_base_top', + ) + + placeholder_base_sidebar = PlaceholderField( + 'trademark_search_base_sidebar', + related_name='search_base_sidebar', + ) + + placeholder_list_top = PlaceholderField( + 'trademark_search_list_top', + related_name='search_list_top', + ) + + placeholder_list_footer = PlaceholderField( + 'trademark_search_list_footer', + related_name='search_list_footer', + ) + + placeholder_detail_top = PlaceholderField( + 'trademark_search_detail_top', + related_name='search_detail_top', + ) + + placeholder_detail_bottom = PlaceholderField( + 'trademark_search_detail_bottom', + related_name='search_detail_bottom', + ) + + placeholder_detail_footer = PlaceholderField( + 'trademark_search_detail_footer', + related_name='search_detail_footer', + ) + + def get_app_title(self): + return getattr(self, 'app_title', _('untitled')) + + +# class TrademarkConfigForm(AppDataForm): +# default_published = forms.BooleanField( +# label=_(u'Post published by default'), required=False, +# initial=getattr(settings, 'search_DEFAULT_PUBLISHED', True)) +# setup_config(searchConfigForm, searchConfig) diff --git a/trademark/lib/__init__.py b/trademark/lib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/trademark/lib/poiskznakov.py b/trademark/lib/poiskznakov.py new file mode 100644 index 0000000..0c83f11 --- /dev/null +++ b/trademark/lib/poiskznakov.py @@ -0,0 +1,100 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import urllib2 +import json +import threading +import time + +class TrademarkSearchAPI(): + login = "Zuykov" + password = "Uodof8awdooLee9f" + + def __init__(self, *args, **options): + pass + + def send_request(self, request): + request['login'] = self.login + request['password'] = self.password + + request_json = json.dumps(request, separators=(',', ':')) + + api_url = "https://api.poiskznakov.ru/" + api_request = urllib2.Request(api_url , request_json, {'Content-Type': 'application/json'}) + + response = urllib2.urlopen(api_request) + + data = json.load(response) + return data + + def search_trademark(self, keyword, similarity=100): + request = { + 'module': 'search', + 'procedure': 'make_search', + 'search_type': 'wdesc', + 'search_string': str(keyword), + 'databases': [21], + 'use_translit': 'true', + 'skip_expired': 'false', + } + + if similarity < 100: + request['search_method'] = 'similarity' + request['minimum_similarity'] = similarity + else: + request['search_method'] = 'containment' + + return self.send_request(request) + + def get_status(self, search_id): + request = { + 'module': 'search', + 'procedure': 'check_status', + 'search_id': search_id + } + + return self.send_request(request) + + def get_results(self, search_id): + # Если не готов результат, то ничего не делаем + status = self.get_status(search_id) + print status + + if status['search_status'] != 'finished': + print status + return {} + + request = { + 'module': 'search', + 'procedure': 'get_result', + 'search_id': search_id, + 'databases': [21] + } + data = self.send_request(request) + + return data['records_list']['21']['records'] + + def get_details(self, ids, keys): + request = { + 'module': 'detail', + 'procedure': 'get_detail_info', + 'marks': ids, + 'access_keys': keys + } + print ids + print keys + data = self.send_request(request) + + return data['records_list']['21']['records'] + + +class SearchResultsThread(threading.Thread): + def __init__(self, keyword, **kwargs): + self.keyword = keyword + super(SearchResultsThread, self).__init__(**kwargs) + + def run(self): + loaded = False + while not loaded: + time.sleep(5) + loaded = self.keyword.load_results() diff --git a/trademark/migrations/0001_initial.py b/trademark/migrations/0001_initial.py new file mode 100644 index 0000000..41e9d34 --- /dev/null +++ b/trademark/migrations/0001_initial.py @@ -0,0 +1,163 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import app_data.fields +import cms.models.fields +import parler.models + + +class Migration(migrations.Migration): + operations = [ + migrations.CreateModel( + name='Keyword', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('request', models.CharField(max_length=200)), + ('slug', models.CharField(max_length=200)), + ('status', models.IntegerField(default=0)), + ('loaded', models.IntegerField(default=0)), + ], + options={ + 'verbose_name': 'keyword', + 'verbose_name_plural': 'keywords', + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Nice', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('nice_id', models.IntegerField()), + ('title', models.CharField(max_length=255)), + ('description', models.TextField()), + ], + options={ + 'verbose_name': 'nice', + 'verbose_name_plural': 'classes', + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Owner', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('title', models.CharField(max_length=255)), + ('country', models.CharField(max_length=4)), + ('address', models.CharField(max_length=255)), + ('legnat', models.CharField(max_length=255)), + ], + options={ + 'verbose_name': 'owner', + 'verbose_name_plural': 'owners', + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Search', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('search_id', models.CharField(max_length=100)), + ('similarity', models.IntegerField()), + ('status', models.CharField(max_length=20)), + ('loaded_at', models.DateField(auto_now_add=True)), + ('keyword', models.ForeignKey(related_name='searches', to='trademark.Keyword')), + ], + options={ + 'verbose_name': 'search', + 'verbose_name_plural': 'searches', + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='SearchResult', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('similarity', models.IntegerField()), + ('search', models.ForeignKey(to='trademark.Search')), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Trademark', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('title', models.CharField(max_length=255)), + ('ext_id', models.IntegerField()), + ('application_id', models.IntegerField()), + ('cert_id', models.IntegerField()), + ('image_url', models.URLField(blank=True)), + ('status', models.CharField(max_length=20)), + ('source_url', models.URLField(blank=True)), + ('application_at', models.DateField(blank=True)), + ('registration_at', models.DateField(blank=True)), + ('expiration_at', models.DateField(blank=True)), + ('renewed_at', models.DateField(blank=True)), + ('priority_at', models.DateField(blank=True)), + ('access_key', models.CharField(max_length=20)), + ('nices', models.ManyToManyField(to='trademark.Nice')), + ('owner', models.ForeignKey(to='trademark.Owner')), + ], + options={ + 'verbose_name': 'trademark', + 'verbose_name_plural': 'trademarks', + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='TrademarkConfig', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('type', models.CharField(max_length=100, verbose_name='type')), + ('namespace', models.CharField(default=None, unique=True, max_length=100, verbose_name='instance namespace')), + ('app_data', app_data.fields.AppDataField(default=b'{}', editable=False)), + ('paginate_by', models.PositiveIntegerField(default=5, help_text='When paginating list views, how many articles per page?', verbose_name='Paginate size')), + ('placeholder_base_sidebar', cms.models.fields.PlaceholderField(related_name='search_base_sidebar', slotname='trademark_search_base_sidebar', editable=False, to='cms.Placeholder', null=True)), + ('placeholder_base_top', cms.models.fields.PlaceholderField(related_name='search_base_top', slotname='trademark_search_base_top', editable=False, to='cms.Placeholder', null=True)), + ('placeholder_detail_bottom', cms.models.fields.PlaceholderField(related_name='search_detail_bottom', slotname='trademark_search_detail_bottom', editable=False, to='cms.Placeholder', null=True)), + ('placeholder_detail_footer', cms.models.fields.PlaceholderField(related_name='search_detail_footer', slotname='trademark_search_detail_footer', editable=False, to='cms.Placeholder', null=True)), + ('placeholder_detail_top', cms.models.fields.PlaceholderField(related_name='search_detail_top', slotname='trademark_search_detail_top', editable=False, to='cms.Placeholder', null=True)), + ('placeholder_list_footer', cms.models.fields.PlaceholderField(related_name='search_list_footer', slotname='trademark_search_list_footer', editable=False, to='cms.Placeholder', null=True)), + ('placeholder_list_top', cms.models.fields.PlaceholderField(related_name='search_list_top', slotname='trademark_search_list_top', editable=False, to='cms.Placeholder', null=True)), + ], + options={ + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='TrademarkConfigTranslation', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('language_code', models.CharField(max_length=15, verbose_name='Language', db_index=True)), + ('app_title', models.CharField(max_length=234, verbose_name='application title')), + ('master', models.ForeignKey(related_name='translations', editable=False, to='trademark.TrademarkConfig', null=True)), + ], + options={ + 'managed': True, + 'db_table': 'trademark_trademarkconfig_translation', + 'db_tablespace': '', + 'default_permissions': (), + 'verbose_name': 'trademark config Translation', + }, + bases=(models.Model,), + ), + migrations.AlterUniqueTogether( + name='trademarkconfigtranslation', + unique_together=set([('language_code', 'master')]), + ), + migrations.AddField( + model_name='searchresult', + name='trademark', + field=models.ForeignKey(to='trademark.Trademark'), + preserve_default=True, + ), + migrations.AddField( + model_name='search', + name='results', + field=models.ManyToManyField(to='trademark.Trademark', through='trademark.SearchResult'), + preserve_default=True, + ), + ] diff --git a/trademark/migrations/__init__.py b/trademark/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/trademark/models.py b/trademark/models.py new file mode 100644 index 0000000..a77341e --- /dev/null +++ b/trademark/models.py @@ -0,0 +1,212 @@ +#-*- coding: utf-8 -*- +from django.db import models +from django.db.models.signals import post_save, pre_save +from django.dispatch import receiver + +from django.utils.translation import ugettext_lazy as _ + +from lib.poiskznakov import TrademarkSearchAPI, SearchResultsThread + +from unidecode import unidecode +from django.template.defaultfilters import slugify +from .cms_appconfig import TrademarkConfig + + +TrademarkAPI = TrademarkSearchAPI() + +class Owner(models.Model): + title = models.CharField(max_length=255) + country = models.CharField(max_length=4) + address = models.CharField(max_length=255) + legnat = models.CharField(max_length=255) + + class Meta: + verbose_name = _('owner') + verbose_name_plural = _('owners') + + def __unicode__(self): # Python 3: def __str__(self): + return self.title + + def __str__(self): + return self.title + + +class Nice(models.Model): + nice_id = models.IntegerField() + title = models.CharField(max_length=255) + description = models.TextField() + + class Meta: + verbose_name = _('nice') + verbose_name_plural = _('classes') + + def __unicode__(self): # Python 3: def __str__(self): + return self.title + + def __str__(self): + return self.title + + +class Trademark(models.Model): + title = models.CharField(max_length=255) + ext_id = models.IntegerField() + application_id = models.IntegerField() + cert_id = models.IntegerField() + owner = models.ForeignKey(Owner) + image_url = models.URLField(blank=True) + nices = models.ManyToManyField(Nice) + status = models.CharField(max_length=20) + source_url = models.URLField(blank=True) + + application_at = models.DateField(blank=True) + registration_at = models.DateField(blank=True) + expiration_at = models.DateField(blank=True) + renewed_at = models.DateField(blank=True) + priority_at = models.DateField(blank=True) + + access_key = models.CharField(max_length=20) + + class Meta: + verbose_name = _('trademark') + verbose_name_plural = _('trademarks') + + def __unicode__(self): # Python 3: def __str__(self): + return self.title + + def __str__(self): + return self.title + + +class Keyword(models.Model): + request = models.CharField(max_length=200) + slug = models.CharField(max_length=200) + status = models.IntegerField(default=0) + loaded = models.IntegerField(default=0) + + class Meta: + verbose_name = _('keyword') + verbose_name_plural = _('keywords') + + def __unicode__(self): # Python 3: def __str__(self): + return self.request + + def __str__(self): + return self.request + + def create_searches(self): + contains = Search(keyword_id=self.id, similarity=100) + similar = Search(keyword_id=self.id, similarity=97) + searches = [contains, similar] + + for search in searches: + search.save() + search.send_request() + + def load_results(self): + for search in self.searches.all(): + if search.status != "finished": + search.get_results() + + if len(self.searches.all()) == len(self.searches.filter(status="finished")): + return True + else: + return False + + +class Search(models.Model): + keyword = models.ForeignKey(Keyword, related_name='searches') + search_id = models.CharField(max_length=100) + results = models.ManyToManyField(Trademark, through='SearchResult') + similarity = models.IntegerField() + status = models.CharField(max_length=20) + loaded_at = models.DateField(auto_now_add=True) + + class Meta: + verbose_name = _('search') + verbose_name_plural = _('searches') + + def __unicode__(self): # Python 3: def __str__(self): + return self.keyword.request + + def __str__(self): + return self.keyword.request + + def send_request(self): + data = TrademarkAPI.search_trademark(keyword=self.keyword.request, similarity=self.similarity) + + self.search_id = data['search_id'] + + self.save() + + + def get_results(self): + results = TrademarkAPI.get_results(self.search_id) + + for key, trademark in results.iteritems(): + owner, created = Owner.objects.get_or_create(title=trademark['owner'][0]['name']) + + instance, created = Trademark.objects.get_or_create( + title=trademark['wdesc'], + application_id=trademark['appnum'], + cert_id=trademark['certnum'], + owner=owner, + image_url=trademark.get('image', ''), + status=trademark['status'], + + application_at=trademark['dateapp'], + registration_at=trademark['datereg'], + + ext_id=trademark['id'], + access_key=trademark['access_key'] + ) + + for nice_id in trademark['icgs']: + nice, created = Nice.objects.get_or_create(nice_id=nice_id) + instance.nices.add(nice) + + instance.save() + + result = SearchResult(search=self, trademark=instance, similarity=trademark['siml']) + + result.save() + + trademark_ids = [int(ext_id) for ext_id in self.results.values_list('ext_id', flat=True)] + trademark_keys = [str(key) for key in self.results.values_list('access_key', flat=True)] + + if len(trademark_ids) == 0: + return + + details = TrademarkAPI.get_details(ids=trademark_ids, keys=trademark_keys) + + for key, trademark in details.iteritems(): + instance = Trademark.objects.get(ext_id=trademark['id']) + instance.owner.name = trademark['owner'][0]['name'] + instance.source_url = trademark.get('source', '') + instance.expiration_at = trademark.get('dateexp', '') + instance.renewed_at = trademark.get('renewed', '') + + instance.save() + + self.status = 'finished' + self.save() + + +class SearchResult(models.Model): + search = models.ForeignKey(Search, on_delete=models.CASCADE) + trademark = models.ForeignKey(Trademark, on_delete=models.CASCADE) + similarity = models.IntegerField() + + +@receiver(pre_save, sender=Keyword) +def update_fields(sender, instance, **kwargs): + if instance._state.adding is True: + instance.slug = slugify(unidecode(instance.request)) + + instance.loaded = instance.loaded + 1 + +@receiver(post_save, sender=Keyword) +def create_searches(sender, instance, created, **kwargs): + if created: + instance.create_searches() + + SearchResultsThread(instance).start() diff --git a/trademark/templates/trademark/base.html b/trademark/templates/trademark/base.html new file mode 100644 index 0000000..f43812a --- /dev/null +++ b/trademark/templates/trademark/base.html @@ -0,0 +1,6 @@ +{% extends 'base.html' %} + +{% block content %} + {% block trademark_content %} + {% endblock %} +{% endblock %} \ No newline at end of file diff --git a/trademark/templates/trademark/search_detail.html b/trademark/templates/trademark/search_detail.html new file mode 100644 index 0000000..5aa0e76 --- /dev/null +++ b/trademark/templates/trademark/search_detail.html @@ -0,0 +1,2 @@ +{% extends "trademark/base.html" %} + diff --git a/trademark/urls.py b/trademark/urls.py new file mode 100644 index 0000000..3f236fc --- /dev/null +++ b/trademark/urls.py @@ -0,0 +1,11 @@ +#-*- coding: utf-8 -*- + +from django.conf.urls import patterns, url + +from . import views + +urlpatterns = patterns('', + # url(r'^search/$', views.IndexView.as_view(), name='index'), + url(r'^online_search/(?P[\w-]+)/$', views.SearchDetailView.as_view(), name='search-detail'), + url(r'^online_search/$', views.Search.as_view(), name='search'), +) diff --git a/trademark/views.py b/trademark/views.py new file mode 100644 index 0000000..3585a10 --- /dev/null +++ b/trademark/views.py @@ -0,0 +1,52 @@ +#-*- coding: utf-8 -*- + +# from django.core.urlresolvers import reverse +# from django.http import HttpResponseRedirect +from django.shortcuts import get_object_or_404 +from django.views import generic +from django.http import HttpResponse +import json + +from .models import * + +class SearchDetailView(generic.DetailView): + model = Keyword + context_object_name = 'post' + template_name = 'trademark/search_detail.html' + slug_field = 'slug' + view_url_name = 'trademark:search-detail' + + +class IndexView(generic.ListView): + template_name = 'trademark/index.html' + context_object_name = 'trademarks' + + def get_queryset(self): + return [] + + + +class Search(generic.View): + # def get(self, request): + # + # return HttpResponse('result') + def get(self, request, slug): + keyword = get_object_or_404(Keyword, slug=slug) + + try: + ids = [str(key) for key in keyword.searches.all().values_list('search_id', flat=True)] + return HttpResponse(json.dumps({ 'search_ids': ids, 'status': 'finished' }), content_type='application/json') + except: + return HttpResponse(json.dumps({ 'status': 'error', 'description': 'Request not found', 'slug': slug }), content_type="application/json") + + + def post(self, request): + keyword = request.POST.get('keyword', '') + + if keyword: + k = Keyword.objects.get_or_create(request=keyword) + k.save() + else: + return HttpResponse(json.dumps({ 'status': 'error', 'description': 'Empty request', 'ext': json.dump(request.POST)}), content_type="application/json") + + return HttpResponse(json.dumps({ 'status': 'ok' }), content_type="application/json")