From 5b454eaf15e0674c56d7f3fcea8ed1649a7675b5 Mon Sep 17 00:00:00 2001 From: Collaborative Community Date: Tue, 11 Dec 2018 17:40:01 +0530 Subject: [PATCH 01/15] Created new branch for ElasticSearch --- BasicArticle/search_indexes.py | 2 +- CollaborationSystem/settings.py | 2 +- Community/models.py | 19 +++++++++--------- Community/search_indexes.py | 18 +++++++++++++++++ .../__pycache__/views.cpython-35.pyc | Bin 1705 -> 1683 bytes docker-compose.yml | 2 +- eventlog/tests/test_api_essearch.py | 2 +- requirements.txt | 2 +- .../indexes/Community/community_text.txt | 1 + templates/search/search.html | 2 +- 10 files changed, 34 insertions(+), 16 deletions(-) create mode 100644 Community/search_indexes.py create mode 100644 templates/search/indexes/Community/community_text.txt diff --git a/BasicArticle/search_indexes.py b/BasicArticle/search_indexes.py index e2c57a3a..14cc450d 100644 --- a/BasicArticle/search_indexes.py +++ b/BasicArticle/search_indexes.py @@ -6,7 +6,7 @@ class ArticlesIndex(indexes.SearchIndex, indexes.Indexable): text = indexes.CharField(document=True, use_template=True) - created_by = indexes.CharField(model_attr='created_by') + # created_by = indexes.CharField(model_attr='created_by') published_on = indexes.DateTimeField(model_attr='published_on') def get_model(self): diff --git a/CollaborationSystem/settings.py b/CollaborationSystem/settings.py index 714300b6..6cbe085f 100644 --- a/CollaborationSystem/settings.py +++ b/CollaborationSystem/settings.py @@ -235,7 +235,7 @@ HAYSTACK_CONNECTIONS = { 'default': { - 'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine', + 'ENGINE': 'haystack.backends.elasticsearch2_backend.Elasticsearch2SearchEngine', 'URL': 'http://'+config('ELASTICSEARCH_ADDRESS')+':9200/', 'INDEX_NAME': 'haystack', }, diff --git a/Community/models.py b/Community/models.py index 319824c0..02513ab8 100644 --- a/Community/models.py +++ b/Community/models.py @@ -14,17 +14,16 @@ def get_file_path(instance, filename): return os.path.join('community', filename) class Community(models.Model): + name = models.CharField(max_length=100) + desc = models.TextField() + image = models.ImageField(null=True, upload_to=get_file_path) + category = models.CharField(max_length=100) + tag_line = models.CharField(null=True, max_length=500) + created_at = models.DateTimeField(null=True, auto_now_add=True) + created_by = models.ForeignKey(User,null =True, related_name='communitycreator') + forum_link = models.CharField(null=True, max_length=100) - name = models.CharField(max_length=100) - desc = models.TextField() - image = models.ImageField(null=True, upload_to=get_file_path) - category = models.CharField(max_length=100) - tag_line = models.CharField(null=True, max_length=500) - created_at = models.DateTimeField(null=True, auto_now_add=True) - created_by = models.ForeignKey(User,null =True, related_name='communitycreator') - forum_link = models.CharField(null=True, max_length=100) - - def __str__(self): + def __str__(self): return self.name diff --git a/Community/search_indexes.py b/Community/search_indexes.py new file mode 100644 index 00000000..d446f248 --- /dev/null +++ b/Community/search_indexes.py @@ -0,0 +1,18 @@ +import datetime +from haystack import indexes +from .models import Community +from django.utils import timezone + + +class CommunityIndex(indexes.SearchIndex, indexes.Indexable): + text = indexes.CharField(document=True, use_template=True) + # created_by = indexes.CharField(model_attr='created_by') + # desc = indexes.CharField(model_attr='desc') + created_at = indexes.DateTimeField(model_attr='created_at') + + def get_model(self): + return Community + + def index_queryset(self, using=None): + # """Used when the entire index for model is updated.""" + return self.get_model().objects.filter(created_at__lte= timezone.make_aware(datetime.datetime.now())) \ No newline at end of file diff --git a/Recommendation_API/__pycache__/views.cpython-35.pyc b/Recommendation_API/__pycache__/views.cpython-35.pyc index 654cfc52296ea95b229785b7716cf52cd5a4c9fa..2a8ccdb6b91dc0b76755fa4ea3eec5a6474b7074 100644 GIT binary patch delta 35 rcmZ3Results {% for result in page.object_list %}

- {{ result.object.title }} + {{ result.object.created_at }}

{% empty %}

No results found.

From a8355a4567367d21350d3e705f3321a55b0cb10f Mon Sep 17 00:00:00 2001 From: Collaborative Community Date: Mon, 7 Jan 2019 15:13:30 +0530 Subject: [PATCH 02/15] search for articles and communities working. Partial search also working --- BasicArticle/models.py | 4 + BasicArticle/search_indexes.py | 6 +- Community/models.py | 6 +- Community/search_indexes.py | 6 +- search/views.py | 274 +++++++++++++++++++++++++++++++-- templates/base.html | 18 ++- templates/search/search.html | 2 +- 7 files changed, 288 insertions(+), 28 deletions(-) diff --git a/BasicArticle/models.py b/BasicArticle/models.py index 31065cd9..f6872cb6 100644 --- a/BasicArticle/models.py +++ b/BasicArticle/models.py @@ -19,6 +19,10 @@ class Articles(models.Model): published_by=models.ForeignKey(User,null=True,related_name='article_publisher') views = models.PositiveIntegerField(default=0) state = models.ForeignKey(States, null=True,related_name='articleworkflow') + + def get_absolute_url(self): + from django.urls import reverse + return reverse('article_view', kwargs={'pk': self.id}) def __str__(self): return self.title diff --git a/BasicArticle/search_indexes.py b/BasicArticle/search_indexes.py index 14cc450d..58765ec1 100644 --- a/BasicArticle/search_indexes.py +++ b/BasicArticle/search_indexes.py @@ -5,13 +5,13 @@ class ArticlesIndex(indexes.SearchIndex, indexes.Indexable): - text = indexes.CharField(document=True, use_template=True) + text = indexes.CharField(document=True, model_attr='title') # created_by = indexes.CharField(model_attr='created_by') - published_on = indexes.DateTimeField(model_attr='published_on') + created_at = indexes.DateTimeField(model_attr='created_at') def get_model(self): return Articles def index_queryset(self, using=None): """Used when the entire index for model is updated.""" - return self.get_model().objects.filter(published_on__lte= timezone.make_aware(datetime.datetime.now())) \ No newline at end of file + return self.get_model().objects.all() \ No newline at end of file diff --git a/Community/models.py b/Community/models.py index 02513ab8..449a1898 100644 --- a/Community/models.py +++ b/Community/models.py @@ -23,8 +23,12 @@ class Community(models.Model): created_by = models.ForeignKey(User,null =True, related_name='communitycreator') forum_link = models.CharField(null=True, max_length=100) + def get_absolute_url(self): + from django.urls import reverse + return reverse('community_view', kwargs={'pk': self.id}) + def __str__(self): - return self.name + return self.name class CommunityMembership(models.Model): diff --git a/Community/search_indexes.py b/Community/search_indexes.py index d446f248..7578f3e5 100644 --- a/Community/search_indexes.py +++ b/Community/search_indexes.py @@ -5,9 +5,11 @@ class CommunityIndex(indexes.SearchIndex, indexes.Indexable): - text = indexes.CharField(document=True, use_template=True) + text = indexes.EdgeNgramField(document=True, model_attr='name') # created_by = indexes.CharField(model_attr='created_by') # desc = indexes.CharField(model_attr='desc') + # name = indexes.CharField(model_attr='name') + # id = indexes.CharField(model_attr='id') created_at = indexes.DateTimeField(model_attr='created_at') def get_model(self): @@ -15,4 +17,4 @@ def get_model(self): def index_queryset(self, using=None): # """Used when the entire index for model is updated.""" - return self.get_model().objects.filter(created_at__lte= timezone.make_aware(datetime.datetime.now())) \ No newline at end of file + return self.get_model().objects.all() \ No newline at end of file diff --git a/search/views.py b/search/views.py index fa2243dc..cdde8574 100644 --- a/search/views.py +++ b/search/views.py @@ -1,17 +1,257 @@ -#from django.shortcuts import render, redirect -#import pysolr -#path= "http://10.129.132.103:8983/solr/collab" -#def search_articles(request): - #if request.method == 'POST': - # searchcriteria = request.POST['searchcriteria'] - # conn=pysolr.Solr(path) - # articles=conn.search('*'+searchcriteria+'*') - # return render(request, 'search.html',{'articles':articles}) - - - -#def IndexDocuments(id,title,body,date): -# conn=pysolr.Solr(path) -# docs = [{'id': id, 'title': title, 'body': body ,'created_at' : str(date) }] -# conn.add(docs) -# return +# encoding: utf-8 + +from __future__ import absolute_import, division, print_function, unicode_literals + +from django.conf import settings +from django.core.paginator import InvalidPage, Paginator +from django.http import Http404 +from django.shortcuts import render + +from haystack.forms import FacetedSearchForm, ModelSearchForm +from haystack.query import EmptySearchQuerySet + +RESULTS_PER_PAGE = getattr(settings, "HAYSTACK_SEARCH_RESULTS_PER_PAGE", 20) + + +class SearchView(object): + template = "search/search.html" + extra_context = {} + query = "" + results = EmptySearchQuerySet() + request = None + form = None + results_per_page = RESULTS_PER_PAGE + + def __init__( + self, + template=None, + load_all=True, + form_class=None, + searchqueryset=None, + results_per_page=None, + ): + self.load_all = load_all + self.form_class = form_class + self.searchqueryset = searchqueryset + + if form_class is None: + self.form_class = ModelSearchForm + + if results_per_page is not None: + self.results_per_page = results_per_page + + if template: + self.template = template + + def __call__(self, request): + """ + Generates the actual response to the search. + + Relies on internal, overridable methods to construct the response. + """ + self.request = request + + self.form = self.build_form() + self.query = self.get_query() + self.results = self.get_results() + + return self.create_response() + + def build_form(self, form_kwargs=None): + """ + Instantiates the form the class should use to process the search query. + """ + data = None + kwargs = {"load_all": self.load_all} + if form_kwargs: + kwargs.update(form_kwargs) + + if len(self.request.GET): + data = self.request.GET + + if self.searchqueryset is not None: + kwargs["searchqueryset"] = self.searchqueryset + + return self.form_class(data, **kwargs) + + def get_query(self): + """ + Returns the query provided by the user. + + Returns an empty string if the query is invalid. + """ + if self.form.is_valid(): + return self.form.cleaned_data["q"] + + return "" + + def get_results(self): + """ + Fetches the results via the form. + + Returns an empty list if there's no query to search with. + """ + return self.form.search() + + def build_page(self): + """ + Paginates the results appropriately. + + In case someone does not want to use Django's built-in pagination, it + should be a simple matter to override this method to do what they would + like. + """ + try: + page_no = int(self.request.GET.get("page", 1)) + except (TypeError, ValueError): + raise Http404("Not a valid number for page.") + + if page_no < 1: + raise Http404("Pages should be 1 or greater.") + + start_offset = (page_no - 1) * self.results_per_page + self.results[start_offset : start_offset + self.results_per_page] + + paginator = Paginator(self.results, self.results_per_page) + + try: + page = paginator.page(page_no) + except InvalidPage: + raise Http404("No such page!") + + return (paginator, page) + + def extra_context(self): + """ + Allows the addition of more context variables as needed. + + Must return a dictionary. + """ + return {} + + def get_context(self): + (paginator, page) = self.build_page() + + context = { + "query": self.query, + "form": self.form, + "page": page, + "paginator": paginator, + "suggestion": None, + } + + if ( + hasattr(self.results, "query") + and self.results.query.backend.include_spelling + ): + context["suggestion"] = self.form.get_suggestion() + + context.update(self.extra_context()) + + return context + + def create_response(self): + """ + Generates the actual HttpResponse to send back to the user. + """ + + context = self.get_context() + + return render(self.request, self.template, context) + + +def search_view_factory(view_class=SearchView, *args, **kwargs): + def search_view(request): + return view_class(*args, **kwargs)(request) + + return search_view + + +class FacetedSearchView(SearchView): + def __init__(self, *args, **kwargs): + # Needed to switch out the default form class. + if kwargs.get("form_class") is None: + kwargs["form_class"] = FacetedSearchForm + + super(FacetedSearchView, self).__init__(*args, **kwargs) + + def build_form(self, form_kwargs=None): + if form_kwargs is None: + form_kwargs = {} + + # This way the form can always receive a list containing zero or more + # facet expressions: + form_kwargs["selected_facets"] = self.request.GET.getlist("selected_facets") + + return super(FacetedSearchView, self).build_form(form_kwargs) + + def extra_context(self): + extra = super(FacetedSearchView, self).extra_context() + extra["request"] = self.request + extra["facets"] = self.results.facet_counts() + return extra + + +def basic_search( + request, + template="search/search.html", + load_all=True, + form_class=ModelSearchForm, + searchqueryset=None, + extra_context=None, + results_per_page=None, +): + """ + A more traditional view that also demonstrate an alternative + way to use Haystack. + + Useful as an example of for basing heavily custom views off of. + + Also has the benefit of thread-safety, which the ``SearchView`` class may + not be. + + Template:: ``search/search.html`` + Context:: + * form + An instance of the ``form_class``. (default: ``ModelSearchForm``) + * page + The current page of search results. + * paginator + A paginator instance for the results. + * query + The query received by the form. + """ + query = "" + results = EmptySearchQuerySet() + + if request.GET.get("q"): + form = form_class(request.GET, searchqueryset=searchqueryset, load_all=load_all) + + if form.is_valid(): + query = form.cleaned_data["q"] + results = form.search() + else: + form = form_class(searchqueryset=searchqueryset, load_all=load_all) + + paginator = Paginator(results, results_per_page or RESULTS_PER_PAGE) + + try: + page = paginator.page(int(request.GET.get("page", 1))) + except InvalidPage: + raise Http404("No such page of results!") + + context = { + "form": form, + "page": page, + "paginator": paginator, + "query": query, + "suggestion": None, + } + + if results.query.backend.include_spelling: + context["suggestion"] = form.get_suggestion() + + if extra_context: + context.update(extra_context) + + return render(request, template, context) diff --git a/templates/base.html b/templates/base.html index 3c4f81d5..577d8c8a 100644 --- a/templates/base.html +++ b/templates/base.html @@ -193,9 +193,19 @@ diff --git a/templates/search/search.html b/templates/search/search.html index 105ff3ad..58e98341 100644 --- a/templates/search/search.html +++ b/templates/search/search.html @@ -19,7 +19,7 @@

Results

{% for result in page.object_list %}

- {{ result.object.created_at }} + {{ result.object.name }} {{ result.object.title }} {{ result.object.created_at }}

{% empty %}

No results found.

From 116778e5729663835e540cc1068a9bf577e8d461 Mon Sep 17 00:00:00 2001 From: Collaborative Community Date: Mon, 7 Jan 2019 15:35:26 +0530 Subject: [PATCH 03/15] reputation/models.py line 33 commented to bypass error --- Reputation/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Reputation/models.py b/Reputation/models.py index f2c191b8..097626ba 100644 --- a/Reputation/models.py +++ b/Reputation/models.py @@ -30,7 +30,8 @@ class FlagReason(models.Model): reason = models.CharField(max_length=200) def __str__(self): - return f'{self.pk} - {self.reason}' + pass + #return f'{self.pk} - {self.reason}' #it will store score of a particular article class ArticleScoreLog(models.Model): From 9935b2c7c633ba0d145d810f951b686d2fd4436f Mon Sep 17 00:00:00 2001 From: Collaborative Community Date: Mon, 21 Jan 2019 14:54:59 +0530 Subject: [PATCH 04/15] faceting without filter --- BasicArticle/views.py | 3 + CollaborationSystem/settings.py | 3 +- CollaborationSystem/urls.py | 28 +++- Community/forms.py | 32 ++++ Community/models.py | 2 +- Community/search_indexes.py | 10 +- Community/urls.py | 10 ++ Community/views.py | 23 ++- search/views.py | 5 + static/js/our_search_code.js | 72 +++++++++ templates/base.html | 9 +- .../indexes/BasicArticle/articles_text.txt | 7 +- .../indexes/Community/community_text.txt | 10 +- templates/search/search.html | 147 +++++++++++++++++- 14 files changed, 349 insertions(+), 12 deletions(-) create mode 100644 Community/forms.py create mode 100644 Community/urls.py create mode 100644 static/js/our_search_code.js diff --git a/BasicArticle/views.py b/BasicArticle/views.py index 81033fd5..1e38d0d2 100644 --- a/BasicArticle/views.py +++ b/BasicArticle/views.py @@ -389,3 +389,6 @@ def article_watch(request, article): class SimpleModelHistoryCompareView(HistoryCompareDetailView): model = Articles + + + diff --git a/CollaborationSystem/settings.py b/CollaborationSystem/settings.py index f43cfce4..23881e46 100644 --- a/CollaborationSystem/settings.py +++ b/CollaborationSystem/settings.py @@ -96,6 +96,7 @@ } MIDDLEWARE = [ + 'corsheaders.middleware.CorsMiddleware', 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', @@ -104,7 +105,6 @@ 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'reversion.middleware.RevisionMiddleware', - 'corsheaders.middleware.CorsMiddleware', 'machina.apps.forum_permission.middleware.ForumPermissionMiddleware', 'social_django.middleware.SocialAuthExceptionMiddleware', 'eventlog.middleware.Middleware', @@ -243,6 +243,7 @@ }, } +HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor' COMMENTS_APP='django_comments_xtd' diff --git a/CollaborationSystem/urls.py b/CollaborationSystem/urls.py index e6001b06..06da571d 100644 --- a/CollaborationSystem/urls.py +++ b/CollaborationSystem/urls.py @@ -36,6 +36,10 @@ from Reputation import views as repuationview from Media import views as mediaview from TaskQueue import views as taskview +from haystack.forms import FacetedSearchForm +from haystack.views import FacetedSearchView +from haystack.query import SearchQuerySet + router = routers.DefaultRouter() router.register(r'articleapi', viewsets.ArticleViewSet) @@ -133,7 +137,10 @@ url(r'^group_content/(?P\d+)/$', group_views.group_content, name='group_content'), url(r'^FAQs/$', web.FAQs, name ='FAQs' ), - url(r'^search/', include('haystack.urls')), + #url(r'^search/', include('haystack.urls')), + # url(r'^$', FacetedSearchView.as_view(form_class=FacetedSearchForm, facet_fields=['name'],template_name='search.html', context_object_name='page_object')), + #url(r'^$', FacetedSearchView.as_view(), name='haystack_search'), + #url(r'^search/', FacetedSearchView(form_class=FacetedSearchForm, searchqueryset = SearchQuerySet().facet('desc'), name='haystack_search')), url(r'^feedback/$', web.provide_feedback, name ='provide_feedback' ), url(r'^contact_us/$', web.contact_us, name ='contact_us' ), @@ -190,10 +197,27 @@ from wiki.urls import get_pattern as get_wiki_pattern from django_nyt.urls import get_pattern as get_nyt_pattern + + + + + +sqs = SearchQuerySet().facet('category') + urlpatterns += [ url(r'^wiki-notifications/', get_nyt_pattern()), - url(r'^wiki/', get_wiki_pattern()) + url(r'^wiki/', get_wiki_pattern()), + #url(r'^search/', FacetedSearchView.as_view(), name='haystack_search'), + url(r'^search/', FacetedSearchView(form_class=FacetedSearchForm, searchqueryset=sqs), name='haystack_search'), + ] + + +# urlpatterns = patterns('haystack.views', +# url(r'^$', FacetedSearchView(form_class=FacetedSearchForm, searchqueryset=sqs), name='haystack_search'), +# ) + if settings.DEBUG: urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + diff --git a/Community/forms.py b/Community/forms.py new file mode 100644 index 00000000..8d627c2a --- /dev/null +++ b/Community/forms.py @@ -0,0 +1,32 @@ +from haystack.forms import FacetedSearchForm + + +class FacetedProductSearchForm(FacetedSearchForm): + + def __init__(self, *args, **kwargs): + data = dict(kwargs.get("data", [])) + self.categorys = data.get('category', []) + #self.brands = data.get('brand', []) + super(FacetedProductSearchForm, self).__init__(*args, **kwargs) + + def search(self): + sqs = super(FacetedProductSearchForm, self).search() + if self.categorys: + query = None + for category in self.categorys: + if query: + query += u' OR ' + else: + query = u'' + query += u'"%s"' % sqs.query.clean(category) + sqs = sqs.narrow(u'category_exact:%s' % query) + # if self.brands: + # query = None + # for brand in self.brands: + # if query: + # query += u' OR ' + # else: + # query = u'' + # query += u'"%s"' % sqs.query.clean(brand) + # sqs = sqs.narrow(u'brand_exact:%s' % query) + return sqs \ No newline at end of file diff --git a/Community/models.py b/Community/models.py index 678d8e37..7bb25f4c 100644 --- a/Community/models.py +++ b/Community/models.py @@ -16,7 +16,7 @@ class Community(models.Model): name = models.CharField(max_length=100) desc = models.TextField() image = models.ImageField(null=True, upload_to=get_file_path) - category = models.CharField(max_length=100) + category = models.CharField(db_index=True, max_length=100) tag_line = models.CharField(null=True, max_length=500) created_at = models.DateTimeField(null=True, auto_now_add=True) created_by = models.ForeignKey(User,null =True, related_name='communitycreator') diff --git a/Community/search_indexes.py b/Community/search_indexes.py index 7578f3e5..975e3f34 100644 --- a/Community/search_indexes.py +++ b/Community/search_indexes.py @@ -2,16 +2,22 @@ from haystack import indexes from .models import Community from django.utils import timezone +from haystack.fields import CharField class CommunityIndex(indexes.SearchIndex, indexes.Indexable): text = indexes.EdgeNgramField(document=True, model_attr='name') # created_by = indexes.CharField(model_attr='created_by') - # desc = indexes.CharField(model_attr='desc') - # name = indexes.CharField(model_attr='name') + + #desc = indexes.TextField(model_attr='desc', faceted=True) + category = indexes.CharField(model_attr='category', faceted=True) + # name = indexes.CharField(model_attr='name', faceted=True) # id = indexes.CharField(model_attr='id') created_at = indexes.DateTimeField(model_attr='created_at') + # for spelling suggestions + suggestions = indexes.FacetCharField() + def get_model(self): return Community diff --git a/Community/urls.py b/Community/urls.py new file mode 100644 index 00000000..b4e63938 --- /dev/null +++ b/Community/urls.py @@ -0,0 +1,10 @@ +# from django.conf.urls import url +# from django.contrib import admin +# from .views import FacetedSearchView +# from .settings import MEDIA_ROOT, MEDIA_URL +# from django.conf.urls.static import static + +# urlpatterns = [ +# url(r'/search/', FacetedSearchView.as_view(), name='haystack_search'), + +# ] + static(MEDIA_URL, document_root=MEDIA_ROOT) \ No newline at end of file diff --git a/Community/views.py b/Community/views.py index bbff59ff..e6427de2 100644 --- a/Community/views.py +++ b/Community/views.py @@ -35,6 +35,13 @@ from metadata.views import create_metadata from metadata.models import MediaMetadata +from django.views.generic import TemplateView +from django.views.generic.detail import DetailView +from haystack.generic_views import FacetedSearchView as BaseFacetedSearchView +from haystack.query import SearchQuerySet + +from .forms import FacetedProductSearchForm + def display_communities(request): if request.method == 'POST': sortby = request.POST['sortby'] @@ -696,4 +703,18 @@ def community_media_create(request): return redirect('home') else: return redirect('login') - \ No newline at end of file + + +from django.views.generic import TemplateView +from django.views.generic.detail import DetailView +from django.http import JsonResponse +from haystack.generic_views import FacetedSearchView as BaseFacetedSearchView +from haystack.query import SearchQuerySet +# tag_analytics/views.py +class FacetedSearchView(BaseFacetedSearchView): + + form_class = FacetedProductSearchForm + facet_fields = ['category'] + template_name = 'search.html' + paginate_by = 3 + context_object_name = 'object_list' diff --git a/search/views.py b/search/views.py index cdde8574..fd6fdb3a 100644 --- a/search/views.py +++ b/search/views.py @@ -127,6 +127,8 @@ def extra_context(self): Must return a dictionary. """ + print (">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", extra) + return {} def get_context(self): @@ -172,6 +174,7 @@ def __init__(self, *args, **kwargs): # Needed to switch out the default form class. if kwargs.get("form_class") is None: kwargs["form_class"] = FacetedSearchForm + print ("#####################################") super(FacetedSearchView, self).__init__(*args, **kwargs) @@ -182,6 +185,7 @@ def build_form(self, form_kwargs=None): # This way the form can always receive a list containing zero or more # facet expressions: form_kwargs["selected_facets"] = self.request.GET.getlist("selected_facets") + print (">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>") return super(FacetedSearchView, self).build_form(form_kwargs) @@ -189,6 +193,7 @@ def extra_context(self): extra = super(FacetedSearchView, self).extra_context() extra["request"] = self.request extra["facets"] = self.results.facet_counts() + print (">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", extra) return extra diff --git a/static/js/our_search_code.js b/static/js/our_search_code.js new file mode 100644 index 00000000..70a71158 --- /dev/null +++ b/static/js/our_search_code.js @@ -0,0 +1,72 @@ +$(function () { + 'use strict'; + + $('#q').autocomplete({ + serviceUrl: "http://127.0.0.1:8000/search/autocomplete/", + minChars: 2, + dataType: 'json', + type: 'GET', + onSelect: function (suggestion) { + console.log( suggestion.value + ', data :' + suggestion.data); + } +}); + +}); + + +function getParameterByName(name, url) { + if (!url) { + url = window.location.href; + } + name = name.replace(/[\[\]]/g, "\\$&"); + var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), + results = regex.exec(url); + if (!results) return null; + if (!results[2]) return ''; + return decodeURIComponent(results[2].replace(/\+/g, " ")); +} + + + + +function onFacetChangeApplied(){ + + var url = window.location.href.split("?")[0]; + var search_query = getParameterByName('q'); + var url_with_search_query = url + '?q=' + search_query + console.log("before>>>>>"+url_with_search_query); + $('input:checkbox.facet').each(function () { + var sThisVal = (this.checked ? $(this).val() : null); + var sThisName = (this.checked ? $(this).attr('category') : null); + if(sThisVal !== null){ + url_with_search_query += '&'+encodeURIComponent(sThisName)+'='+encodeURIComponent(sThisVal); + } + }); + console.log(">>>>>>>>>>>>before page change>>>>>>>"+url_with_search_query); + location.href = url_with_search_query; + console.log(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"+url_with_search_query); + return true; +} + + +function getQueryParams(){ + var vars = {}, hash; + var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); + for(var i = 0; i < hashes.length; i++) + { + hash = hashes[i].split('='); + vars[hash[1]] = hash[0] ; + } + return vars; +} + + +$( document ).ready(function() { + var all_params = getQueryParams(); + console.log(); + $.each( all_params, function( key, value ) { + id = decodeURIComponent(key).replace(/\s/g,''); + $('#'+id).attr('checked', 'checked'); + }); + +}); diff --git a/templates/base.html b/templates/base.html index 326dfddc..be4954be 100644 --- a/templates/base.html +++ b/templates/base.html @@ -202,7 +202,6 @@ From 1b260ca4c1e51aa194424f8ee8f49cf5ee103a53 Mon Sep 17 00:00:00 2001 From: Minali24 Date: Fri, 1 Mar 2019 16:58:49 +0530 Subject: [PATCH 10/15] search with published articles --- BasicArticle/search_indexes.py | 1 + CollaborationSystem/urls.py | 16 +- Community/forms.py | 2 - Community/search_indexes.py | 6 - Community/urls.py | 10 - Community/views.py | 16 - static/js/jquery.autocomplete.js | 992 ------------------------------- static/js/our_search_code.js | 74 --- templates/base.html | 2 - templates/search_result.html | 120 +--- 10 files changed, 31 insertions(+), 1208 deletions(-) delete mode 100644 static/js/jquery.autocomplete.js delete mode 100644 static/js/our_search_code.js diff --git a/BasicArticle/search_indexes.py b/BasicArticle/search_indexes.py index 58765ec1..c561fa6d 100644 --- a/BasicArticle/search_indexes.py +++ b/BasicArticle/search_indexes.py @@ -8,6 +8,7 @@ class ArticlesIndex(indexes.SearchIndex, indexes.Indexable): text = indexes.CharField(document=True, model_attr='title') # created_by = indexes.CharField(model_attr='created_by') created_at = indexes.DateTimeField(model_attr='created_at') + state = indexes.CharField(model_attr='state') def get_model(self): return Articles diff --git a/CollaborationSystem/urls.py b/CollaborationSystem/urls.py index a87531ef..af4efad7 100644 --- a/CollaborationSystem/urls.py +++ b/CollaborationSystem/urls.py @@ -37,7 +37,7 @@ from Media import views as mediaview from TaskQueue import views as taskview from Community.forms import FacetedSearchForm -from Community.views import FacetedSearchView, autocomplete +from Community.views import FacetedSearchView from haystack.query import SearchQuerySet from Categories import views as categoryview from metadata import views as metadataview @@ -203,24 +203,14 @@ from wiki.urls import get_pattern as get_wiki_pattern from django_nyt.urls import get_pattern as get_nyt_pattern - - - - - -# sqs = SearchQuerySet().facet('category') - urlpatterns += [ url(r'^wiki-notifications/', get_nyt_pattern()), url(r'^wiki/', get_wiki_pattern()), url(r'^search/', FacetedSearchView.as_view(), name='haystack_search'), - url(r'^search/autocomplete/$', autocomplete), - #url(r'^search/find/', FacetedSearchView.as_view(), name='haystack_search'), - #url(r'^search/', FacetedSearchView.as_view(form_class=FacetedSearchForm, searchqueryset=sqs), name='haystack_search'), - -] +] + if settings.DEBUG: urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/Community/forms.py b/Community/forms.py index 80968852..6f55c1ea 100644 --- a/Community/forms.py +++ b/Community/forms.py @@ -103,7 +103,6 @@ class FacetedProductSearchForm(FacetedSearchForm): def __init__(self, *args, **kwargs): data = dict(kwargs.get("data", [])) self.categorys = data.get('category', []) - #self.brands = data.get('brand', []) super(FacetedProductSearchForm, self).__init__(*args, **kwargs) def search(self): @@ -117,5 +116,4 @@ def search(self): query = u'' query += u'"%s"' % sqs.query.clean(category) sqs = sqs.narrow(u'category_exact:%s' % query) - print ("2.>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Inside FacetedSearchForm sqs = "+str(sqs.query)) return sqs diff --git a/Community/search_indexes.py b/Community/search_indexes.py index 98895a06..e17a5858 100644 --- a/Community/search_indexes.py +++ b/Community/search_indexes.py @@ -7,13 +7,7 @@ class CommunityIndex(indexes.SearchIndex, indexes.Indexable): text = indexes.EdgeNgramField(document=True, model_attr='name') - # created_by = indexes.CharField(model_attr='created_by') - - #desc = indexes.TextField(model_attr='desc', faceted=True) category = indexes.CharField(model_attr='category', faceted=True) - # name = indexes.CharField(model_attr='name', faceted=True) - # id = indexes.CharField(model_attr='id') - created_at = indexes.DateTimeField(model_attr='created_at') # for spelling suggestions diff --git a/Community/urls.py b/Community/urls.py index b4e63938..e69de29b 100644 --- a/Community/urls.py +++ b/Community/urls.py @@ -1,10 +0,0 @@ -# from django.conf.urls import url -# from django.contrib import admin -# from .views import FacetedSearchView -# from .settings import MEDIA_ROOT, MEDIA_URL -# from django.conf.urls.static import static - -# urlpatterns = [ -# url(r'/search/', FacetedSearchView.as_view(), name='haystack_search'), - -# ] + static(MEDIA_URL, document_root=MEDIA_ROOT) \ No newline at end of file diff --git a/Community/views.py b/Community/views.py index 33f10e7c..e590827d 100644 --- a/Community/views.py +++ b/Community/views.py @@ -725,22 +725,6 @@ def community_media_create(request): return redirect('login') -def autocomplete(request): - print("Entered auto-complete function") - sqs = SearchQuerySet().autocomplete( - content_auto=request.GET.get( - 'query', - ''))[ - :5] - s = [] - for result in sqs: - d = {"value": result.title, "data": result.object.slug} - s.append(d) - output = {'suggestions': s} - - print("autocomplete suggestions = "+str(output)) - return JsonResponse(output) - class FacetedSearchView(BaseFacetedSearchView): form_class = FacetedProductSearchForm diff --git a/static/js/jquery.autocomplete.js b/static/js/jquery.autocomplete.js deleted file mode 100644 index 78a15939..00000000 --- a/static/js/jquery.autocomplete.js +++ /dev/null @@ -1,992 +0,0 @@ -/** -* Ajax Autocomplete for jQuery, version %version% -* (c) 2015 Tomas Kirda -* -* Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license. -* For details, see the web site: https://github.com/devbridge/jQuery-Autocomplete -*/ - -/*jslint browser: true, white: true, single: true, this: true, multivar: true */ -/*global define, window, document, jQuery, exports, require */ - -// Expose plugin as an AMD module if AMD loader is present: -(function (factory) { - "use strict"; - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - define(['jquery'], factory); - } else if (typeof exports === 'object' && typeof require === 'function') { - // Browserify - factory(require('jquery')); - } else { - // Browser globals - factory(jQuery); - } -}(function ($) { - 'use strict'; - - var - utils = (function () { - return { - escapeRegExChars: function (value) { - return value.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&"); - }, - createNode: function (containerClass) { - var div = document.createElement('div'); - div.className = containerClass; - div.style.position = 'absolute'; - div.style.display = 'none'; - return div; - } - }; - }()), - - keys = { - ESC: 27, - TAB: 9, - RETURN: 13, - LEFT: 37, - UP: 38, - RIGHT: 39, - DOWN: 40 - }; - - function Autocomplete(el, options) { - var noop = $.noop, - that = this, - defaults = { - ajaxSettings: {}, - autoSelectFirst: false, - appendTo: document.body, - serviceUrl: null, - lookup: null, - onSelect: null, - width: 'auto', - minChars: 1, - maxHeight: 300, - deferRequestBy: 0, - params: {}, - formatResult: Autocomplete.formatResult, - delimiter: null, - zIndex: 9999, - type: 'GET', - noCache: false, - onSearchStart: noop, - onSearchComplete: noop, - onSearchError: noop, - preserveInput: false, - containerClass: 'autocomplete-suggestions', - tabDisabled: false, - dataType: 'text', - currentRequest: null, - triggerSelectOnValidInput: true, - preventBadQueries: true, - lookupFilter: function (suggestion, originalQuery, queryLowerCase) { - return suggestion.value.toLowerCase().indexOf(queryLowerCase) !== -1; - }, - paramName: 'query', - transformResult: function (response) { - return typeof response === 'string' ? $.parseJSON(response) : response; - }, - showNoSuggestionNotice: false, - noSuggestionNotice: 'No results', - orientation: 'bottom', - forceFixPosition: false - }; - - // Shared variables: - that.element = el; - that.el = $(el); - that.suggestions = []; - that.badQueries = []; - that.selectedIndex = -1; - that.currentValue = that.element.value; - that.intervalId = 0; - that.cachedResponse = {}; - that.onChangeInterval = null; - that.onChange = null; - that.isLocal = false; - that.suggestionsContainer = null; - that.noSuggestionsContainer = null; - that.options = $.extend({}, defaults, options); - that.classes = { - selected: 'autocomplete-selected', - suggestion: 'autocomplete-suggestion' - }; - that.hint = null; - that.hintValue = ''; - that.selection = null; - - // Initialize and set options: - that.initialize(); - that.setOptions(options); - } - - Autocomplete.utils = utils; - - $.Autocomplete = Autocomplete; - - Autocomplete.formatResult = function (suggestion, currentValue) { - // Do not replace anything if there current value is empty - if (!currentValue) { - return suggestion.value; - } - - var pattern = '(' + utils.escapeRegExChars(currentValue) + ')'; - - return suggestion.value - .replace(new RegExp(pattern, 'gi'), '$1<\/strong>') - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/<(\/?strong)>/g, '<$1>'); - }; - - Autocomplete.prototype = { - - killerFn: null, - - initialize: function () { - var that = this, - suggestionSelector = '.' + that.classes.suggestion, - selected = that.classes.selected, - options = that.options, - container; - - // Remove autocomplete attribute to prevent native suggestions: - that.element.setAttribute('autocomplete', 'off'); - - that.killerFn = function (e) { - if (!$(e.target).closest('.' + that.options.containerClass).length) { - that.killSuggestions(); - that.disableKillerFn(); - } - }; - - // html() deals with many types: htmlString or Element or Array or jQuery - that.noSuggestionsContainer = $('
') - .html(this.options.noSuggestionNotice).get(0); - - that.suggestionsContainer = Autocomplete.utils.createNode(options.containerClass); - - container = $(that.suggestionsContainer); - - container.appendTo(options.appendTo); - - // Only set width if it was provided: - if (options.width !== 'auto') { - container.css('width', options.width); - } - - // Listen for mouse over event on suggestions list: - container.on('mouseover.autocomplete', suggestionSelector, function () { - that.activate($(this).data('index')); - }); - - // Deselect active element when mouse leaves suggestions container: - container.on('mouseout.autocomplete', function () { - that.selectedIndex = -1; - container.children('.' + selected).removeClass(selected); - }); - - // Listen for click event on suggestions list: - container.on('click.autocomplete', suggestionSelector, function () { - that.select($(this).data('index')); - return false; - }); - - that.fixPositionCapture = function () { - if (that.visible) { - that.fixPosition(); - } - }; - - $(window).on('resize.autocomplete', that.fixPositionCapture); - - that.el.on('keydown.autocomplete', function (e) { that.onKeyPress(e); }); - that.el.on('keyup.autocomplete', function (e) { that.onKeyUp(e); }); - that.el.on('blur.autocomplete', function () { that.onBlur(); }); - that.el.on('focus.autocomplete', function () { that.onFocus(); }); - that.el.on('change.autocomplete', function (e) { that.onKeyUp(e); }); - that.el.on('input.autocomplete', function (e) { that.onKeyUp(e); }); - }, - - onFocus: function () { - var that = this; - - that.fixPosition(); - - if (that.el.val().length >= that.options.minChars) { - that.onValueChange(); - } - }, - - onBlur: function () { - this.enableKillerFn(); - }, - - abortAjax: function () { - var that = this; - if (that.currentRequest) { - that.currentRequest.abort(); - that.currentRequest = null; - } - }, - - setOptions: function (suppliedOptions) { - var that = this, - options = that.options; - - $.extend(options, suppliedOptions); - - that.isLocal = $.isArray(options.lookup); - - if (that.isLocal) { - options.lookup = that.verifySuggestionsFormat(options.lookup); - } - - options.orientation = that.validateOrientation(options.orientation, 'bottom'); - - // Adjust height, width and z-index: - $(that.suggestionsContainer).css({ - 'max-height': options.maxHeight + 'px', - 'width': options.width + 'px', - 'z-index': options.zIndex - }); - }, - - - clearCache: function () { - this.cachedResponse = {}; - this.badQueries = []; - }, - - clear: function () { - this.clearCache(); - this.currentValue = ''; - this.suggestions = []; - }, - - disable: function () { - var that = this; - that.disabled = true; - clearInterval(that.onChangeInterval); - that.abortAjax(); - }, - - enable: function () { - this.disabled = false; - }, - - fixPosition: function () { - // Use only when container has already its content - - var that = this, - $container = $(that.suggestionsContainer), - containerParent = $container.parent().get(0); - // Fix position automatically when appended to body. - // In other cases force parameter must be given. - if (containerParent !== document.body && !that.options.forceFixPosition) { - return; - } - - // Choose orientation - var orientation = that.options.orientation, - containerHeight = $container.outerHeight(), - height = that.el.outerHeight(), - offset = that.el.offset(), - styles = { 'top': offset.top, 'left': offset.left }; - - if (orientation === 'auto') { - var viewPortHeight = $(window).height(), - scrollTop = $(window).scrollTop(), - topOverflow = -scrollTop + offset.top - containerHeight, - bottomOverflow = scrollTop + viewPortHeight - (offset.top + height + containerHeight); - - orientation = (Math.max(topOverflow, bottomOverflow) === topOverflow) ? 'top' : 'bottom'; - } - - if (orientation === 'top') { - styles.top += -containerHeight; - } else { - styles.top += height; - } - - // If container is not positioned to body, - // correct its position using offset parent offset - if(containerParent !== document.body) { - var opacity = $container.css('opacity'), - parentOffsetDiff; - - if (!that.visible){ - $container.css('opacity', 0).show(); - } - - parentOffsetDiff = $container.offsetParent().offset(); - styles.top -= parentOffsetDiff.top; - styles.left -= parentOffsetDiff.left; - - if (!that.visible){ - $container.css('opacity', opacity).hide(); - } - } - - if (that.options.width === 'auto') { - styles.width = that.el.outerWidth() + 'px'; - } - - $container.css(styles); - }, - - enableKillerFn: function () { - var that = this; - $(document).on('click.autocomplete', that.killerFn); - }, - - disableKillerFn: function () { - var that = this; - $(document).off('click.autocomplete', that.killerFn); - }, - - killSuggestions: function () { - var that = this; - that.stopKillSuggestions(); - that.intervalId = window.setInterval(function () { - if (that.visible) { - // No need to restore value when - // preserveInput === true, - // because we did not change it - if (!that.options.preserveInput) { - that.el.val(that.currentValue); - } - - that.hide(); - } - - that.stopKillSuggestions(); - }, 50); - }, - - stopKillSuggestions: function () { - window.clearInterval(this.intervalId); - }, - - isCursorAtEnd: function () { - var that = this, - valLength = that.el.val().length, - selectionStart = that.element.selectionStart, - range; - - if (typeof selectionStart === 'number') { - return selectionStart === valLength; - } - if (document.selection) { - range = document.selection.createRange(); - range.moveStart('character', -valLength); - return valLength === range.text.length; - } - return true; - }, - - onKeyPress: function (e) { - var that = this; - - // If suggestions are hidden and user presses arrow down, display suggestions: - if (!that.disabled && !that.visible && e.which === keys.DOWN && that.currentValue) { - that.suggest(); - return; - } - - if (that.disabled || !that.visible) { - return; - } - - switch (e.which) { - case keys.ESC: - that.el.val(that.currentValue); - that.hide(); - break; - case keys.RIGHT: - if (that.hint && that.options.onHint && that.isCursorAtEnd()) { - that.selectHint(); - break; - } - return; - case keys.TAB: - if (that.hint && that.options.onHint) { - that.selectHint(); - return; - } - if (that.selectedIndex === -1) { - that.hide(); - return; - } - that.select(that.selectedIndex); - if (that.options.tabDisabled === false) { - return; - } - break; - case keys.RETURN: - if (that.selectedIndex === -1) { - that.hide(); - return; - } - that.select(that.selectedIndex); - break; - case keys.UP: - that.moveUp(); - break; - case keys.DOWN: - that.moveDown(); - break; - default: - return; - } - - // Cancel event if function did not return: - e.stopImmediatePropagation(); - e.preventDefault(); - }, - - onKeyUp: function (e) { - var that = this; - - if (that.disabled) { - return; - } - - switch (e.which) { - case keys.UP: - case keys.DOWN: - return; - } - - clearInterval(that.onChangeInterval); - - if (that.currentValue !== that.el.val()) { - that.findBestHint(); - if (that.options.deferRequestBy > 0) { - // Defer lookup in case when value changes very quickly: - that.onChangeInterval = setInterval(function () { - that.onValueChange(); - }, that.options.deferRequestBy); - } else { - that.onValueChange(); - } - } - }, - - onValueChange: function () { - var that = this, - options = that.options, - value = that.el.val(), - query = that.getQuery(value); - - if (that.selection && that.currentValue !== query) { - that.selection = null; - (options.onInvalidateSelection || $.noop).call(that.element); - } - - clearInterval(that.onChangeInterval); - that.currentValue = value; - that.selectedIndex = -1; - - // Check existing suggestion for the match before proceeding: - if (options.triggerSelectOnValidInput && that.isExactMatch(query)) { - that.select(0); - return; - } - - if (query.length < options.minChars) { - that.hide(); - } else { - that.getSuggestions(query); - } - }, - - isExactMatch: function (query) { - var suggestions = this.suggestions; - - return (suggestions.length === 1 && suggestions[0].value.toLowerCase() === query.toLowerCase()); - }, - - getQuery: function (value) { - var delimiter = this.options.delimiter, - parts; - - if (!delimiter) { - return value; - } - parts = value.split(delimiter); - return $.trim(parts[parts.length - 1]); - }, - - getSuggestionsLocal: function (query) { - var that = this, - options = that.options, - queryLowerCase = query.toLowerCase(), - filter = options.lookupFilter, - limit = parseInt(options.lookupLimit, 10), - data; - - data = { - suggestions: $.grep(options.lookup, function (suggestion) { - return filter(suggestion, query, queryLowerCase); - }) - }; - - if (limit && data.suggestions.length > limit) { - data.suggestions = data.suggestions.slice(0, limit); - } - - return data; - }, - - getSuggestions: function (q) { - var response, - that = this, - options = that.options, - serviceUrl = options.serviceUrl, - params, - cacheKey, - ajaxSettings; - - options.params[options.paramName] = q; - params = options.ignoreParams ? null : options.params; - - if (options.onSearchStart.call(that.element, options.params) === false) { - return; - } - - if ($.isFunction(options.lookup)){ - options.lookup(q, function (data) { - that.suggestions = data.suggestions; - that.suggest(); - options.onSearchComplete.call(that.element, q, data.suggestions); - }); - return; - } - - if (that.isLocal) { - response = that.getSuggestionsLocal(q); - } else { - if ($.isFunction(serviceUrl)) { - serviceUrl = serviceUrl.call(that.element, q); - } - cacheKey = serviceUrl + '?' + $.param(params || {}); - response = that.cachedResponse[cacheKey]; - } - - if (response && $.isArray(response.suggestions)) { - that.suggestions = response.suggestions; - that.suggest(); - options.onSearchComplete.call(that.element, q, response.suggestions); - } else if (!that.isBadQuery(q)) { - that.abortAjax(); - - ajaxSettings = { - url: serviceUrl, - data: params, - type: options.type, - dataType: options.dataType - }; - - $.extend(ajaxSettings, options.ajaxSettings); - - that.currentRequest = $.ajax(ajaxSettings).done(function (data) { - var result; - that.currentRequest = null; - result = options.transformResult(data, q); - that.processResponse(result, q, cacheKey); - options.onSearchComplete.call(that.element, q, result.suggestions); - }).fail(function (jqXHR, textStatus, errorThrown) { - options.onSearchError.call(that.element, q, jqXHR, textStatus, errorThrown); - }); - } else { - options.onSearchComplete.call(that.element, q, []); - } - }, - - isBadQuery: function (q) { - if (!this.options.preventBadQueries){ - return false; - } - - var badQueries = this.badQueries, - i = badQueries.length; - - while (i--) { - if (q.indexOf(badQueries[i]) === 0) { - return true; - } - } - - return false; - }, - - hide: function () { - var that = this, - container = $(that.suggestionsContainer); - - if ($.isFunction(that.options.onHide) && that.visible) { - that.options.onHide.call(that.element, container); - } - - that.visible = false; - that.selectedIndex = -1; - clearInterval(that.onChangeInterval); - $(that.suggestionsContainer).hide(); - that.signalHint(null); - }, - - suggest: function () { - if (!this.suggestions.length) { - if (this.options.showNoSuggestionNotice) { - this.noSuggestions(); - } else { - this.hide(); - } - return; - } - - var that = this, - options = that.options, - groupBy = options.groupBy, - formatResult = options.formatResult, - value = that.getQuery(that.currentValue), - className = that.classes.suggestion, - classSelected = that.classes.selected, - container = $(that.suggestionsContainer), - noSuggestionsContainer = $(that.noSuggestionsContainer), - beforeRender = options.beforeRender, - html = '', - category, - formatGroup = function (suggestion, index) { - var currentCategory = suggestion.data[groupBy]; - - if (category === currentCategory){ - return ''; - } - - category = currentCategory; - - return '
' + category + '
'; - }; - - if (options.triggerSelectOnValidInput && that.isExactMatch(value)) { - that.select(0); - return; - } - - // Build suggestions inner HTML: - $.each(that.suggestions, function (i, suggestion) { - if (groupBy){ - html += formatGroup(suggestion, value, i); - } - - html += '
' + formatResult(suggestion, value, i) + '
'; - }); - - this.adjustContainerWidth(); - - noSuggestionsContainer.detach(); - container.html(html); - - if ($.isFunction(beforeRender)) { - beforeRender.call(that.element, container, that.suggestions); - } - - that.fixPosition(); - container.show(); - - // Select first value by default: - if (options.autoSelectFirst) { - that.selectedIndex = 0; - container.scrollTop(0); - container.children('.' + className).first().addClass(classSelected); - } - - that.visible = true; - that.findBestHint(); - }, - - noSuggestions: function() { - var that = this, - container = $(that.suggestionsContainer), - noSuggestionsContainer = $(that.noSuggestionsContainer); - - this.adjustContainerWidth(); - - // Some explicit steps. Be careful here as it easy to get - // noSuggestionsContainer removed from DOM if not detached properly. - noSuggestionsContainer.detach(); - container.empty(); // clean suggestions if any - container.append(noSuggestionsContainer); - - that.fixPosition(); - - container.show(); - that.visible = true; - }, - - adjustContainerWidth: function() { - var that = this, - options = that.options, - width, - container = $(that.suggestionsContainer); - - // If width is auto, adjust width before displaying suggestions, - // because if instance was created before input had width, it will be zero. - // Also it adjusts if input width has changed. - if (options.width === 'auto') { - width = that.el.outerWidth(); - container.css('width', width > 0 ? width : 300); - } - }, - - findBestHint: function () { - var that = this, - value = that.el.val().toLowerCase(), - bestMatch = null; - - if (!value) { - return; - } - - $.each(that.suggestions, function (i, suggestion) { - var foundMatch = suggestion.value.toLowerCase().indexOf(value) === 0; - if (foundMatch) { - bestMatch = suggestion; - } - return !foundMatch; - }); - - that.signalHint(bestMatch); - }, - - signalHint: function (suggestion) { - var hintValue = '', - that = this; - if (suggestion) { - hintValue = that.currentValue + suggestion.value.substr(that.currentValue.length); - } - if (that.hintValue !== hintValue) { - that.hintValue = hintValue; - that.hint = suggestion; - (this.options.onHint || $.noop)(hintValue); - } - }, - - verifySuggestionsFormat: function (suggestions) { - // If suggestions is string array, convert them to supported format: - if (suggestions.length && typeof suggestions[0] === 'string') { - return $.map(suggestions, function (value) { - return { value: value, data: null }; - }); - } - - return suggestions; - }, - - validateOrientation: function(orientation, fallback) { - orientation = $.trim(orientation || '').toLowerCase(); - - if($.inArray(orientation, ['auto', 'bottom', 'top']) === -1){ - orientation = fallback; - } - - return orientation; - }, - - processResponse: function (result, originalQuery, cacheKey) { - var that = this, - options = that.options; - - result.suggestions = that.verifySuggestionsFormat(result.suggestions); - - // Cache results if cache is not disabled: - if (!options.noCache) { - that.cachedResponse[cacheKey] = result; - if (options.preventBadQueries && !result.suggestions.length) { - that.badQueries.push(originalQuery); - } - } - - // Return if originalQuery is not matching current query: - if (originalQuery !== that.getQuery(that.currentValue)) { - return; - } - - that.suggestions = result.suggestions; - that.suggest(); - }, - - activate: function (index) { - var that = this, - activeItem, - selected = that.classes.selected, - container = $(that.suggestionsContainer), - children = container.find('.' + that.classes.suggestion); - - container.find('.' + selected).removeClass(selected); - - that.selectedIndex = index; - - if (that.selectedIndex !== -1 && children.length > that.selectedIndex) { - activeItem = children.get(that.selectedIndex); - $(activeItem).addClass(selected); - return activeItem; - } - - return null; - }, - - selectHint: function () { - var that = this, - i = $.inArray(that.hint, that.suggestions); - - that.select(i); - }, - - select: function (i) { - var that = this; - that.hide(); - that.onSelect(i); - that.disableKillerFn(); - }, - - moveUp: function () { - var that = this; - - if (that.selectedIndex === -1) { - return; - } - - if (that.selectedIndex === 0) { - $(that.suggestionsContainer).children().first().removeClass(that.classes.selected); - that.selectedIndex = -1; - that.el.val(that.currentValue); - that.findBestHint(); - return; - } - - that.adjustScroll(that.selectedIndex - 1); - }, - - moveDown: function () { - var that = this; - - if (that.selectedIndex === (that.suggestions.length - 1)) { - return; - } - - that.adjustScroll(that.selectedIndex + 1); - }, - - adjustScroll: function (index) { - var that = this, - activeItem = that.activate(index); - - if (!activeItem) { - return; - } - - var offsetTop, - upperBound, - lowerBound, - heightDelta = $(activeItem).outerHeight(); - - offsetTop = activeItem.offsetTop; - upperBound = $(that.suggestionsContainer).scrollTop(); - lowerBound = upperBound + that.options.maxHeight - heightDelta; - - if (offsetTop < upperBound) { - $(that.suggestionsContainer).scrollTop(offsetTop); - } else if (offsetTop > lowerBound) { - $(that.suggestionsContainer).scrollTop(offsetTop - that.options.maxHeight + heightDelta); - } - - if (!that.options.preserveInput) { - that.el.val(that.getValue(that.suggestions[index].value)); - } - that.signalHint(null); - }, - - onSelect: function (index) { - var that = this, - onSelectCallback = that.options.onSelect, - suggestion = that.suggestions[index]; - - that.currentValue = that.getValue(suggestion.value); - - if (that.currentValue !== that.el.val() && !that.options.preserveInput) { - that.el.val(that.currentValue); - } - - that.signalHint(null); - that.suggestions = []; - that.selection = suggestion; - - if ($.isFunction(onSelectCallback)) { - onSelectCallback.call(that.element, suggestion); - } - }, - - getValue: function (value) { - var that = this, - delimiter = that.options.delimiter, - currentValue, - parts; - - if (!delimiter) { - return value; - } - - currentValue = that.currentValue; - parts = currentValue.split(delimiter); - - if (parts.length === 1) { - return value; - } - - return currentValue.substr(0, currentValue.length - parts[parts.length - 1].length) + value; - }, - - dispose: function () { - var that = this; - that.el.off('.autocomplete').removeData('autocomplete'); - that.disableKillerFn(); - $(window).off('resize.autocomplete', that.fixPositionCapture); - $(that.suggestionsContainer).remove(); - } - }; - - // Create chainable jQuery plugin: - $.fn.autocomplete = $.fn.devbridgeAutocomplete = function (options, args) { - var dataKey = 'autocomplete'; - // If function invoked without argument return - // instance of the first matched element: - if (!arguments.length) { - return this.first().data(dataKey); - } - - return this.each(function () { - var inputElement = $(this), - instance = inputElement.data(dataKey); - - if (typeof options === 'string') { - if (instance && typeof instance[options] === 'function') { - instance[options](args); - } - } else { - // If instance already exists, destroy it: - if (instance && instance.dispose) { - instance.dispose(); - } - instance = new Autocomplete(this, options); - inputElement.data(dataKey, instance); - } - }); - }; -})); diff --git a/static/js/our_search_code.js b/static/js/our_search_code.js deleted file mode 100644 index d8f2c9c0..00000000 --- a/static/js/our_search_code.js +++ /dev/null @@ -1,74 +0,0 @@ -$(function () { - console.log("Hiiiiiiiii") - 'use strict'; - - - $('#q').autocomplete({ - serviceUrl: "http://127.0.0.1:8000/search/autocomplete/", - minChars: 2, - dataType: 'json', - type: 'GET', - onSelect: function (suggestion) { - console.log( suggestion.value + ', data :' + suggestion.data); - } -}); - -}); - - -function getParameterByName(name, url) { - if (!url) { - url = window.location.href; - } - name = name.replace(/[\[\]]/g, "\\$&"); - var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), - results = regex.exec(url); - if (!results) return null; - if (!results[2]) return ''; - return decodeURIComponent(results[2].replace(/\+/g, " ")); -} - - - - -function onFacetChangeApplied(){ - - var url = window.location.href.split("?")[0]; - var search_query = getParameterByName('q'); - var url_with_search_query = url + '?q=' + search_query - console.log("before>>>>>"+url_with_search_query); - $('input:checkbox.facet').each(function () { - var sThisVal = (this.checked ? $(this).val() : null); - var sThisName = (this.checked ? $(this).attr('name') : null); - if(sThisVal !== null){ - url_with_search_query += '&'+encodeURIComponent(sThisName)+'='+encodeURIComponent(sThisVal); - } - }); - console.log(">>>>>>>>>>>>before page change>>>>>>>"+url_with_search_query); - location.href = url_with_search_query; - console.log(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"+url_with_search_query); - return true; -} - - -function getQueryParams(){ - var vars = {}, hash; - var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); - for(var i = 0; i < hashes.length; i++) - { - hash = hashes[i].split('='); - vars[hash[1]] = hash[0] ; - } - return vars; -} - - -$( document ).ready(function() { - var all_params = getQueryParams(); - console.log(); - $.each( all_params, function( key, value ) { - id = decodeURIComponent(key).replace(/\s/g,''); - $('#'+id).attr('checked', 'checked'); - }); - -}); diff --git a/templates/base.html b/templates/base.html index 4ab5578d..39ba66a0 100644 --- a/templates/base.html +++ b/templates/base.html @@ -290,10 +290,8 @@

Site Theme by

{% block javascript %}{% endblock %} - - diff --git a/templates/search_result.html b/templates/search_result.html index 0e2693cb..3a45f9c1 100644 --- a/templates/search_result.html +++ b/templates/search_result.html @@ -9,74 +9,23 @@

Search

  - - -
- - -
- -
+ - - - -{% if facets %} -facets: {{ facets.fields.category }} -
-

Filters

-
- {% if facets.fields.category %} -
Filter by category
- {% for category in facets.fields.category %} - {% if category.1 != 0 %} -
- {{ category.0 }} ({{ category.1 }}) -
- {% endif %} - {% endfor %} - {% endif %} -
-
- -
- - -
-{% endif %} - - + + + {% if query %} +

Communities

+ {% for result in object_list|slice:":1" %} + +
- {% if query %} -

Results

-
-
-

Communities

- - {% for result in object_list %} - {% if result.object.name %} - - -
- {{myhtml|safe}}{% autoescape off%} - + {{myhtml|safe}}
{% if result.object.image %} @@ -108,33 +57,27 @@

{{result.object.name|truncatewords:2}}

{{result.object.category|truncatewords:2 }}
- - {% endautoescape%} -
- - {% endif %} - - - - - - {% empty %} -

No results found.

+
+ + {% else %} +

No results found.

+ {% endif %} + + {% endfor %}
-
+ -
+

Articles

- {% for result in object_list %} + {% for result in object_list|slice:":1" %} {% if result.object.title %} + + {% if result.object.state.name == "publish" %}
- {{myhtml|safe}}{% autoescape off%} + {{myhtml|safe}}
@@ -168,16 +111,14 @@

{{result.object.name|truncatewords:2}}

- {% endautoescape%} +
- {% endif %} - - + {% endif %} + {% else %} + No articles found. + {% endif %} - {% empty %}

No results found.

{% endfor %} @@ -200,10 +141,3 @@

{{result.object.name|truncatewords:2}}

{% endblock %} -{% block javascript %} - - - - - -{% endblock %} \ No newline at end of file From 9f3dd5bb317638b91ed5cc8597d0eee9931620e9 Mon Sep 17 00:00:00 2001 From: Minali24 Date: Wed, 6 Mar 2019 15:42:28 +0530 Subject: [PATCH 11/15] Media search for image working --- Media/models.py | 6 ++++- Media/search_indexes.py | 23 ++++++++++++++++ templates/search_result.html | 52 ++++++++++++++++++++++++++++++++---- 3 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 Media/search_indexes.py diff --git a/Media/models.py b/Media/models.py index b77b2c19..11e7a097 100644 --- a/Media/models.py +++ b/Media/models.py @@ -31,4 +31,8 @@ class Media(models.Model): published_on=models.DateTimeField(null=True) published_by=models.ForeignKey(User,null=True,related_name='media_publisher') views = models.PositiveIntegerField(default=0) - state = models.ForeignKey(States, null=True,related_name='media_workflow') \ No newline at end of file + state = models.ForeignKey(States, null=True,related_name='media_workflow') + + def get_absolute_url(self): + from django.urls import reverse + return reverse('media_view', kwargs={'pk': self.id}) \ No newline at end of file diff --git a/Media/search_indexes.py b/Media/search_indexes.py new file mode 100644 index 00000000..7d7c44dd --- /dev/null +++ b/Media/search_indexes.py @@ -0,0 +1,23 @@ +import datetime +from haystack import indexes +from .models import Media +from django.utils import timezone +from haystack.fields import CharField + + +class MediaIndex(indexes.SearchIndex, indexes.Indexable): + text = indexes.EdgeNgramField(document=True, model_attr='title') + #category = indexes.CharField(model_attr='category', faceted=True) + mediafile = indexes.CharField(model_attr='mediafile') + state = indexes.CharField(model_attr='state') + + + # for spelling suggestions + #suggestions = indexes.FacetCharField() + + def get_model(self): + return Media + + def index_queryset(self, using=None): + # """Used when the entire index for model is updated.""" + return self.get_model().objects.all() \ No newline at end of file diff --git a/templates/search_result.html b/templates/search_result.html index 3a45f9c1..537158e0 100644 --- a/templates/search_result.html +++ b/templates/search_result.html @@ -19,9 +19,9 @@

Search

{% if query %}

Communities

+
+ {% for result in object_list|slice:":1" %} - -
{% if result.object.name %}
@@ -69,14 +69,15 @@

{{result.object.name|truncatewords:2}}

- +

Articles

+
{% for result in object_list|slice:":1" %} - {% if result.object.title %} + {% if result.object.body %} {% if result.object.state.name == "publish" %} -
+ {{myhtml|safe}}
@@ -125,6 +126,47 @@

{{result.object.name|truncatewords:2}}

+
+

Media

+
+ {% for result in object_list %} +
{{ result.object.mediatype }}
+ {% if result.object.mediafile %} + + + + {% endif %} + {% endfor %} + +
+ + + + {% if page.has_previous or page.has_next %} From 5d32dd0927d8279a9006ebe9914d172b8eed8c11 Mon Sep 17 00:00:00 2001 From: Minali24 Date: Mon, 11 Mar 2019 17:40:57 +0530 Subject: [PATCH 12/15] Resource filter working completely --- CollaborationSystem/urls.py | 3 +- Community/views.py | 22 ++- search/views.py | 14 +- templates/search_result.html | 355 +++++++++++++++++++++-------------- 4 files changed, 247 insertions(+), 147 deletions(-) diff --git a/CollaborationSystem/urls.py b/CollaborationSystem/urls.py index af4efad7..811638be 100644 --- a/CollaborationSystem/urls.py +++ b/CollaborationSystem/urls.py @@ -41,6 +41,7 @@ from haystack.query import SearchQuerySet from Categories import views as categoryview from metadata import views as metadataview +from search import views as SearchView router = routers.DefaultRouter() @@ -207,7 +208,7 @@ url(r'^wiki-notifications/', get_nyt_pattern()), url(r'^wiki/', get_wiki_pattern()), url(r'^search/', FacetedSearchView.as_view(), name='haystack_search'), - + # url(r'^search_category/', SearchView.search_queries, name='search_queries'), ] diff --git a/Community/views.py b/Community/views.py index e590827d..57723b83 100644 --- a/Community/views.py +++ b/Community/views.py @@ -725,7 +725,7 @@ def community_media_create(request): return redirect('login') -class FacetedSearchView(BaseFacetedSearchView): +class FacetedSearchView(BaseFacetedSearchView, TemplateView): form_class = FacetedProductSearchForm facet_fields = ['category'] @@ -733,3 +733,23 @@ class FacetedSearchView(BaseFacetedSearchView): #paginate_by = 3 #context_object_name = 'object_list' + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + print("self.request.GET >>>>>>>>>>>>>>>>>>>>> ", self.request.GET) + try: + if 'community' in self.request.GET: + context['community'] = self.request.GET['community'] + if 'article' in self.request.GET: + context['article'] = self.request.GET['article'] + if 'image' in self.request.GET: + context['image'] = self.request.GET['image'] + if 'audio' in self.request.GET: + context['audio'] = self.request.GET['audio'] + if 'video' in self.request.GET: + context['video'] = self.request.GET['video'] + if 'query' in self.request.GET: + context['query'] = self.request.GET['query'] + except: + pass + return context + diff --git a/search/views.py b/search/views.py index fd6fdb3a..939baae1 100644 --- a/search/views.py +++ b/search/views.py @@ -4,7 +4,7 @@ from django.conf import settings from django.core.paginator import InvalidPage, Paginator -from django.http import Http404 +from django.http import Http404, HttpResponse, HttpRequest from django.shortcuts import render from haystack.forms import FacetedSearchForm, ModelSearchForm @@ -161,6 +161,18 @@ def create_response(self): return render(self.request, self.template, context) + # def search_queries(self): + # return render(self.template) + # return HttpResponse('hello') + # print ("############### request.GET ::::::::::::::::: ") + # context = self.get_context() + + # return render(self.request, self.template, {hello:'hello'}) + +def search_queries(request): + query = request.GET['q'] + comm = request.GET['community'] + return render(request, 'search_result.html', {'query':query}) def search_view_factory(view_class=SearchView, *args, **kwargs): def search_view(request): diff --git a/templates/search_result.html b/templates/search_result.html index 537158e0..3fb68178 100644 --- a/templates/search_result.html +++ b/templates/search_result.html @@ -5,181 +5,248 @@

Search

+ + + + + + + +
+ + -
   
- - + + + +
+ + + {% if query %} + {% if community %}

Communities

- - {% for result in object_list|slice:":1" %} - - {% if result.object.name %} -
- {{myhtml|safe}} -
-
- {% if result.object.image %} - image - {% else %} - default - {%endif%} - -
-

{{result.object.name}}

-
{{result.object.tag_line|truncatewords:5}}
-

{{ result.object.desc |striptags|truncatewords:20}}

- - View More - - - {% if result.object.image %} - - View Image - - {% else %} - - View Image - - {% endif %} - -
-

{{result.object.name|truncatewords:2}}

- {{result.object.category|truncatewords:2 }} -
+ {% for result in object_list|slice:":1" %} + {% if result.object.name %} +
+ {{myhtml|safe}} +
+
+ {% if result.object.image %} + image + {% else %} + default + {%endif%} + +
+

{{result.object.name}}

+
{{result.object.tag_line|truncatewords:5}}
+

{{ result.object.desc |striptags|truncatewords:20}}

+ + View More + + + {% if result.object.image %} + + View Image + + {% else %} + + View Image + + {% endif %}
-
- - {% else %} -

No results found.

- {% endif %} - - - {% endfor %} +

{{result.object.name|truncatewords:2}}

+ {{result.object.category|truncatewords:2 }} +
+
+
+ {% else %} +

No communities found.

+ {% endif %} + + {% empty %} +

No results found.

+ {% endfor %} -
- +
+ {% endif %} + +
+ {% if article %} +

Articles

+
+ {% for result in object_list|slice:":1" %} + {% if result.object.body %} + + {% if result.object.state.name == "publish" %} + + + {{myhtml|safe}} +
+
+
+ {% if result.object.image %} + image + {% else %} + default + {%endif%} + +
+

{{result.object.title}}

+
{{result.object.tag_line|truncatewords:5}}
+

{{ result.object.desc |striptags|truncatewords:20}}

+ + View More + + + {% if result.object.image %} + + View Image + + {% else %} + + View Image + + {% endif %} -
-

Articles

-
- {% for result in object_list|slice:":1" %} - {% if result.object.body %} - - {% if result.object.state.name == "publish" %} - - - {{myhtml|safe}} -
-
-
- {% if result.object.image %} - image - {% else %} - default - {%endif%} - -
-

{{result.object.title}}

-
{{result.object.tag_line|truncatewords:5}}
-

{{ result.object.desc |striptags|truncatewords:20}}

- - View More - - - {% if result.object.image %} - - View Image - - {% else %} - - View Image - - {% endif %} - -
-

{{result.object.name|truncatewords:2}}

- {{result.object.category|truncatewords:2 }} -
-
- -
+

{{result.object.name|truncatewords:2}}

+ {{result.object.category|truncatewords:2 }} +
+
+
+ + {% endif %} + {% else %} + No articles found. + {% endif %} - {% endif %} - {% else %} - No articles found. - {% endif %} + {% empty %} +

No results found.

+ {% endfor %} - {% empty %} -

No results found.

- {% endfor %} +
+ {% endif %} +
+ + {% if image %} +

Images

+
+ {% for result in object_list %} + {% if result.object.mediatype == "IMAGE" %} + +
+ +
+ + {% else %} + No images found. + {% endif %} + + {% empty %} +

No results found.

+ {% endfor %}
+ {% endif %}
-

Media

+ + {% if audio %} +

Audios

- {% for result in object_list %} -
{{ result.object.mediatype }}
- {% if result.object.mediafile %} - - - {% endif %} - {% endfor %} +
+ + {% if video %} +

Videos

+
+ {% for result in object_list %} + {% if result.object.mediatype == "VIDEO" %} + + {% else %} + No videos found. + {% endif %} + + {% empty %} +

No results found.

+ {% endfor %}
+ {% endif %} - - - - - - {% if page.has_previous or page.has_next %} -
- {% if page.has_previous %}{% endif %}« Previous{% if page.has_previous %}{% endif %} - | - {% if page.has_next %}{% endif %}Next »{% if page.has_next %}{% endif %} -
- {% endif %} + {% if page.has_previous or page.has_next %} +
+ {% if page.has_previous %}{% endif %}« Previous{% if page.has_previous %}{% endif %} + | + {% if page.has_next %}{% endif %}Next »{% if page.has_next %}{% endif %} +
+ {% endif %} {% else %} {# Show some example queries to run, maybe query syntax, something else? #} {% endif %} - {% endblock %} From 4158ea16574e7251bbf4a2cf55da30f4d42c0b14 Mon Sep 17 00:00:00 2001 From: Minali24 Date: Tue, 12 Mar 2019 20:08:01 +0530 Subject: [PATCH 13/15] checkbox for search items implemented --- templates/search_result.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/search_result.html b/templates/search_result.html index 3fb68178..35d6452e 100644 --- a/templates/search_result.html +++ b/templates/search_result.html @@ -2,7 +2,7 @@ {% block content %}

Search

- +
From 072972336e933b134ce3c24139440a2f2964b347 Mon Sep 17 00:00:00 2001 From: Nithin S Date: Mon, 18 Mar 2019 14:56:06 +0530 Subject: [PATCH 14/15] Automate workflow --- BasicArticle/forms.py | 5 ++-- BasicArticle/views.py | 9 +++++- CollaborationSystem/urls.py | 5 ++++ Community/views.py | 5 +++- templates/transition.html | 50 +++++++++++++++++++++++++++++++ workflow/models.py | 4 ++- workflow/views.py | 60 +++++++++++++++++++++++++++++-------- 7 files changed, 121 insertions(+), 17 deletions(-) create mode 100644 templates/transition.html diff --git a/BasicArticle/forms.py b/BasicArticle/forms.py index bfa91acd..18232bf3 100644 --- a/BasicArticle/forms.py +++ b/BasicArticle/forms.py @@ -18,13 +18,14 @@ class Meta: fields = ['title', 'body', 'image', 'state', 'tags'] def __init__(self, *args, **kwargs): + role = kwargs.pop('role', None) super().__init__(*args, **kwargs) self.fields['title'].widget.attrs.update({'class': 'form-control'}) self.fields['image'].widget.attrs.update({'class': 'file', 'data-allowed-file-extensions':'["jpeg", "jpg","png"]', 'data-show-upload':'false', 'data-show-preview':'false', 'data-msg-placeholder':'Select article image for upload...'}) self.fields['image'].required = False self.fields['state'].widget.attrs.update({'class': 'form-control'}) self.fields['tags'].widget.attrs.update({'class': 'form-control'}) - states = getStatesCommunity(self.instance.state.name) + states = getStatesCommunity(self.instance.state.name, role) self.fields['state'].queryset = States.objects.filter(name__in=states) if not settings.REALTIME_EDITOR: @@ -45,4 +46,4 @@ def __init__(self, *args, **kwargs): self.fields['image'].required = False self.fields['tags'].widget.attrs.update({'class': 'form-control'}) if not settings.REALTIME_EDITOR: - self.fields['body'].widget.attrs.update({'class': 'form-control'}) \ No newline at end of file + self.fields['body'].widget.attrs.update({'class': 'form-control'}) diff --git a/BasicArticle/views.py b/BasicArticle/views.py index 8d571412..a56853b9 100644 --- a/BasicArticle/views.py +++ b/BasicArticle/views.py @@ -179,6 +179,14 @@ class ArticleEditView(UpdateView): context_object_name = 'article' success_url = 'article_view' + def get_form_kwargs(self): + """ + Returns the keyword arguments for instantiating the form. + """ + kwargs = super(ArticleEditView, self).get_form_kwargs() + kwargs.update({'role': self.get_communityrole(self.request, self.get_community())}) + return kwargs + def get(self, request, *args, **kwargs): if request.user.is_authenticated: self.object = self.get_object() @@ -189,7 +197,6 @@ def get(self, request, *args, **kwargs): return redirect('article_view',pk=self.object.pk) community = self.get_community() if self.is_communitymember(request, community): - role = self.get_communityrole(request, community) if canEditResourceCommunity(self.object.state.name, role.name, self.object, request): response=super(ArticleEditView, self).get(request, *args, **kwargs) if settings.REALTIME_EDITOR: diff --git a/CollaborationSystem/urls.py b/CollaborationSystem/urls.py index 8b134d14..c8b5579c 100644 --- a/CollaborationSystem/urls.py +++ b/CollaborationSystem/urls.py @@ -38,6 +38,8 @@ from TaskQueue import views as taskview from Categories import views as categoryview from metadata import views as metadataview +from workflow import views as workflowview +from django.views.generic import TemplateView from rest_framework_simplejwt.views import ( TokenObtainPairView, TokenRefreshView, @@ -197,6 +199,9 @@ url(r'^community/(?P\d+)/media/(?P\d+)/metadata_create/$', metadataview.MetadataCreateView.as_view(), name='metadata_create'), url(r'^media/(?P\d+)/metadata_update/(?P\d+)$', metadataview.MetadataUpdateView.as_view(), name='metadata_update'), + + url(r'^workflow/transition$', workflowview.getAllStates, name='transition'), + url(r'^workflow/transition/create$', workflowview.createTransitions, name='create_transition'), ] from wiki.urls import get_pattern as get_wiki_pattern diff --git a/Community/views.py b/Community/views.py index f8142714..db066322 100644 --- a/Community/views.py +++ b/Community/views.py @@ -430,7 +430,10 @@ def create_forum(self, name, desc): try: cursor = connection.cursor() cursor.execute(''' select tree_id from forum_forum order by tree_id DESC limit 1''') - tree_id = cursor.fetchone()[0] + 1 + try: + tree_id = cursor.fetchone()[0] + 1 + except: + tree_id = 0 slug = "-".join(name.lower().split()) #return HttpResponse(str(tree_id)) insert_stmt = ( diff --git a/templates/transition.html b/templates/transition.html new file mode 100644 index 00000000..b52922f4 --- /dev/null +++ b/templates/transition.html @@ -0,0 +1,50 @@ +{% extends 'base.html' %} + +{% load widget_tweaks %} + +{% load static %} + +{% block breadcrumb %} + + +{% endblock %} + +{% block content %} + +{% if user.is_authenticated %} + + {% csrf_token %} + {% for role in roles %} +

{{ role }}

+
+
+
+ + + {% for state_name in states %} + + {% endfor %} + + {% for state_row in states %} + + + {% for state_col in states %} + + {% endfor %} + + + {% endfor %} +
{{state_name}}
{{ state_row }} + +
+
+
+ {% endfor %} + + +{% endif %} +
+{% endblock %} +{% block javascript %} + +{% endblock %} diff --git a/workflow/models.py b/workflow/models.py index 1db71073..dd6ae1b4 100644 --- a/workflow/models.py +++ b/workflow/models.py @@ -15,8 +15,10 @@ def __str__(self): class Transitions(models.Model): name = models.CharField(null=True, max_length=100) + community = models.ForeignKey('Community.Community', null=True, related_name='community') + role = models.ForeignKey(Roles, null=True, related_name='role') from_state = models.ForeignKey(States, null=True,related_name='fromtransitions') to_state = models.ForeignKey(States, null=True,related_name='totransitions') def __str__(self): - return self.name \ No newline at end of file + return self.name diff --git a/workflow/views.py b/workflow/views.py index 5cef83d9..6e9d10d0 100644 --- a/workflow/views.py +++ b/workflow/views.py @@ -1,6 +1,7 @@ from django.shortcuts import render, redirect from django.contrib import messages - +from workflow.models import States, Transitions +from django.contrib.auth.models import Group as Roles def canEditResourceCommunity(state, role, resource, request): if state=='publishable' and role=='author': @@ -14,17 +15,52 @@ def canEditResourceCommunity(state, role, resource, request): return False return True -def getStatesCommunity(current_state): +def getStatesCommunity(current_state, role): + state_query = Transitions.objects.value_list(role=role, from_state=current_state) states = [] - if current_state == 'draft': - states.append("draft") - states.append("visible") - if current_state == 'visible': - states.append("visible") - states.append("publishable") - if current_state == 'publishable': - states.append("publishable") - states.append("visible") - states.append("publish") + for value in state_query: + states.append(value[0]) return states +def getAllStates(request): + state_query = States.objects.all() + states = [] + roles = [] + roles_query = Roles.objects.all() + for role in roles_query: + roles.append(role.name) + for value in state_query: + states.append(value.name) + return render(request, 'transition.html', {'states':states, 'roles':roles}) + +def createTransitions(request): + if request.method == 'POST': + state_query = States.objects.all() + states = [] + roles = [] + role_ids = dict() + state_ids = dict() + roles_query = Roles.objects.all() + for role in roles_query: + roles.append(role.name) + role_ids[role.name] = role.id + for value in state_query: + states.append(value.name) + state_ids[value.name] = value.id + + + for role in roles: + for state_from in states: + for state_to in states: + if request.POST.get(role+'-'+state_from+'-'+state_to, False): + role_id = role_ids[role] + from_state_id = state_ids[state_from] + to_state_id = state_ids[state_to] + + transition = Transitions.objects.get_or_create(name=role+'-'+state_from+'-'+state_to, + from_state_id=from_state_id, + to_state_id=to_state_id, + role_id=role_id) + + + return render(request, 'transition.html', {'states':states, 'roles':roles}) From c93963fecdab795be052ca31d3c290b6c4e39bf5 Mon Sep 17 00:00:00 2001 From: shon Date: Mon, 18 Mar 2019 16:28:42 +0530 Subject: [PATCH 15/15] workflow migrations --- .../migrations/0003_auto_20190318_1054.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 workflow/migrations/0003_auto_20190318_1054.py diff --git a/workflow/migrations/0003_auto_20190318_1054.py b/workflow/migrations/0003_auto_20190318_1054.py new file mode 100644 index 00000000..d6c272ab --- /dev/null +++ b/workflow/migrations/0003_auto_20190318_1054.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.18 on 2019-03-18 10:54 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('Community', '0005_community_image_thumbnail'), + ('auth', '0008_alter_user_username_max_length'), + ('workflow', '0002_auto_20190110_1419'), + ] + + operations = [ + migrations.AddField( + model_name='transitions', + name='community', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='community', to='Community.Community'), + ), + migrations.AddField( + model_name='transitions', + name='role', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='role', to='auth.Group'), + ), + ]