deleted bookmarks app

remove-default-role
Jigar 2018-02-23 19:57:58 +05:30
parent 0a4a287767
commit ab55c92bb4
17 changed files with 146 additions and 398 deletions

View File

@ -1,24 +0,0 @@
:mod:`readthedocs.bookmarks`
============================
:mod:`readthedocs.bookmarks.admin`
----------------------------------
.. automodule:: readthedocs.bookmarks.admin
:members:
:mod:`readthedocs.bookmarks.models`
-----------------------------------
.. automodule:: readthedocs.bookmarks.models
:members:
:mod:`readthedocs.bookmarks.urls`
---------------------------------
.. automodule:: readthedocs.bookmarks.urls
:members:
:mod:`readthedocs.bookmarks.views`
----------------------------------
.. automodule:: readthedocs.bookmarks.views
:members:

View File

@ -1,11 +0,0 @@
"""Django admin interface for `~bookmarks.models.Bookmark`."""
from __future__ import absolute_import
from django.contrib import admin
from readthedocs.bookmarks.models import Bookmark
class BookmarkAdmin(admin.ModelAdmin):
list_display = ('project', 'date', 'url')
admin.site.register(Bookmark, BookmarkAdmin)

View File

@ -1,37 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from __future__ import absolute_import
from django.db import models, migrations
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
('builds', '0001_initial'),
('projects', '0002_add_importedfile_model'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Bookmark',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('page', models.CharField(max_length=255, verbose_name='Page')),
('date', models.DateTimeField(auto_now_add=True, verbose_name='Date')),
('url', models.CharField(max_length=255, null=True, verbose_name='URL', blank=True)),
('project', models.ForeignKey(related_name='bookmarks', verbose_name='Project', to='projects.Project')),
('user', models.ForeignKey(related_name='bookmarks', verbose_name='User', to=settings.AUTH_USER_MODEL)),
('version', models.ForeignKey(related_name='bookmarks', verbose_name='Version', to='builds.Version')),
],
options={
'ordering': ['-date'],
},
),
migrations.AlterUniqueTogether(
name='bookmark',
unique_together=set([('user', 'project', 'version', 'page')]),
),
]

View File

@ -1,42 +0,0 @@
"""Models for the bookmarks app."""
from __future__ import absolute_import
from builtins import object
from django.db import models
from django.contrib.auth.models import User
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _, ugettext
from readthedocs.builds.models import Version
from readthedocs.projects.models import Project
@python_2_unicode_compatible
class Bookmark(models.Model):
"""A user's bookmark of a ``Project``, ``Version``, and page."""
user = models.ForeignKey(User, verbose_name=_('User'),
related_name='bookmarks')
project = models.ForeignKey(Project, verbose_name=_('Project'),
related_name='bookmarks')
version = models.ForeignKey(Version, verbose_name=_('Version'),
related_name='bookmarks')
page = models.CharField(_('Page'), max_length=255)
date = models.DateTimeField(_('Date'), auto_now_add=True)
url = models.CharField(_('URL'), max_length=255, null=True, blank=True)
class Meta(object):
ordering = ['-date']
unique_together = ('user', 'project', 'version', 'page')
def __str__(self):
return ugettext(u"Bookmark %(url)s for %(user)s (%(pk)s)") % {
'url': self.url,
'user': self.user,
'pk': self.pk,
}
def get_absolute_url(self):
return self.url

View File

@ -1,29 +0,0 @@
"""URL config for the bookmarks app."""
from __future__ import absolute_import
from django.conf.urls import url
from readthedocs.bookmarks.views import BookmarkListView
from readthedocs.bookmarks.views import BookmarkAddView, BookmarkRemoveView
from readthedocs.bookmarks.views import BookmarkExistsView
urlpatterns = [
url(r'^$',
BookmarkListView.as_view(),
name='bookmark_list'),
url(r'^add/$',
BookmarkAddView.as_view(),
name='bookmarks_add'),
url(r'^remove/(?P<bookmark_pk>[-\w]+)/$',
BookmarkRemoveView.as_view(),
name='bookmark_remove'),
url(r'^remove/$',
BookmarkRemoveView.as_view(),
name='bookmark_remove_json'),
url(r'^exists/$',
BookmarkExistsView.as_view(),
name='bookmark_exists'),
]

View File

@ -1,200 +0,0 @@
# -*- coding: utf-8 -*-
"""Views for the bookmarks app."""
from __future__ import (
absolute_import, division, print_function, unicode_literals)
import json
from django.contrib.auth.decorators import login_required
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse
from django.http import (
HttpResponse, HttpResponseBadRequest, HttpResponseRedirect)
from django.shortcuts import get_object_or_404, render
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.views.generic import ListView, View
from readthedocs.bookmarks.models import Bookmark
from readthedocs.projects.models import Project
# These views are CSRF exempt because of Django's CSRF middleware failing here
# https://github.com/django/django/blob/stable/1.6.x/django/middleware/csrf.py#L135-L159
# We don't have a valid referrer because we're on a subdomain
class BookmarkExistsView(View):
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
return super(BookmarkExistsView,
self).dispatch(request, *args, **kwargs)
def get(self, request):
return HttpResponse(
content=json.dumps({'error': 'You must POST!'}),
content_type='application/json',
status=405,
)
def post(self, request, *args, **kwargs):
"""
Returns:
- 200 response with exists = True in json if bookmark exists.
- 404 with exists = False in json if no matching bookmark is found.
- 400 if json data is missing any one of: project, version, page.
"""
post_json = json.loads(request.body)
try:
project = post_json['project']
version = post_json['version']
page = post_json['page']
except KeyError:
return HttpResponseBadRequest(
content=json.dumps({'error': 'Invalid parameters'}),
)
try:
Bookmark.objects.get(
project__slug=project,
version__slug=version,
page=page,
)
except ObjectDoesNotExist:
return HttpResponse(
content=json.dumps({'exists': False}),
status=404,
content_type='application/json',
)
return HttpResponse(
content=json.dumps({'exists': True}),
status=200,
content_type='application/json',
)
class BookmarkListView(ListView):
"""Displays all of a logged-in user's bookmarks."""
model = Bookmark
@method_decorator(login_required)
def dispatch(self, request, *args, **kwargs):
return super(BookmarkListView, self).dispatch(request, *args, **kwargs)
def get_queryset(self):
return Bookmark.objects.filter(user=self.request.user)
class BookmarkAddView(View):
"""Adds bookmarks in response to POST requests."""
@method_decorator(login_required)
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
return super(BookmarkAddView, self).dispatch(request, *args, **kwargs)
def get(self, request):
return HttpResponse(
content=json.dumps({'error': 'You must POST!'}),
content_type='application/json',
status=405,
)
def post(self, request, *args, **kwargs):
"""
Add a new bookmark for the current user.
Points at ``project``, ``version``, ``page``, and ``url``.
"""
post_json = json.loads(request.body)
try:
project_slug = post_json['project']
version_slug = post_json['version']
page_slug = post_json['page']
url = post_json['url']
except KeyError:
return HttpResponseBadRequest(
content=json.dumps({'error': 'Invalid parameters'}),
)
try:
project = Project.objects.get(slug=project_slug)
version = project.versions.get(slug=version_slug)
except ObjectDoesNotExist:
return HttpResponseBadRequest(
content=json.dumps(
{'error': 'Project or Version does not exist'}),
)
Bookmark.objects.get_or_create(
user=request.user,
url=url,
project=project,
version=version,
page=page_slug,
)
return HttpResponse(
json.dumps({'added': True}),
status=201,
content_type='application/json',
)
class BookmarkRemoveView(View):
"""
Deletes a user's bookmark in response to a POST request.
Renders a delete? confirmation page in response to a GET request.
"""
@method_decorator(login_required)
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
return super(BookmarkRemoveView,
self).dispatch(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
return render(request, 'bookmarks/bookmark_delete.html')
def post(self, request, *args, **kwargs):
"""
Delete a bookmark.
Uses the primary key from the URL or JSON data from the request.
"""
if 'bookmark_pk' in kwargs:
bookmark = get_object_or_404(Bookmark, pk=kwargs['bookmark_pk'])
bookmark.delete()
return HttpResponseRedirect(reverse('bookmark_list'))
try:
post_json = json.loads(request.body)
project = Project.objects.get(slug=post_json['project'])
version = project.versions.get(slug=post_json['version'])
url = post_json['url']
page = post_json['page']
except KeyError:
return HttpResponseBadRequest(
json.dumps({'error': 'Invalid parameters'}),
)
bookmark = get_object_or_404(
Bookmark,
user=request.user,
url=url,
project=project,
version=version,
page=page,
)
bookmark.delete()
return HttpResponse(
json.dumps({'removed': True}),
status=200,
content_type='application/json',
)

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.12 on 2018-02-17 11:21
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('gold', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='golduser',
name='level',
field=models.CharField(choices=[(b'v1-org-5', b'$5/mo'), (b'v1-org-10', b'$10/mo'), (b'v1-org-15', b'$15/mo'), (b'v1-org-20', b'$20/mo'), (b'v1-org-50', b'$50/mo'), (b'v1-org-100', b'$100/mo')], default=b'v1-org-5', max_length=20, verbose_name='Level'),
),
]

View File

@ -0,0 +1,56 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.12 on 2018-02-17 11:21
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('integrations', '0002_add-webhook'),
]
operations = [
migrations.CreateModel(
name='BitbucketWebhook',
fields=[
],
options={
'proxy': True,
},
bases=('integrations.integration',),
),
migrations.CreateModel(
name='GenericAPIWebhook',
fields=[
],
options={
'proxy': True,
},
bases=('integrations.integration',),
),
migrations.CreateModel(
name='GitHubWebhook',
fields=[
],
options={
'proxy': True,
},
bases=('integrations.integration',),
),
migrations.CreateModel(
name='GitLabWebhook',
fields=[
],
options={
'proxy': True,
},
bases=('integrations.integration',),
),
migrations.AlterField(
model_name='integration',
name='integration_type',
field=models.CharField(choices=[('github_webhook', 'GitHub incoming webhook'), ('bitbucket_webhook', 'Bitbucket incoming webhook'), ('gitlab_webhook', 'GitLab incoming webhook'), ('api_webhook', 'Generic API incoming webhook')], max_length=32, verbose_name='Integration type'),
),
]

View File

@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.12 on 2018-02-17 11:21
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('projects', '0023_migrate-alias-slug'),
]
operations = [
migrations.AlterField(
model_name='domain',
name='canonical',
field=models.BooleanField(default=False, help_text='This Domain is the primary one where the documentation is served from'),
),
migrations.AlterField(
model_name='domain',
name='count',
field=models.IntegerField(default=0, help_text='Number of times this domain has been hit'),
),
migrations.AlterField(
model_name='project',
name='allow_promos',
field=models.BooleanField(default=True, help_text='If unchecked, users will still see community ads.', verbose_name='Allow paid advertising'),
),
migrations.AlterField(
model_name='project',
name='comment_moderation',
field=models.BooleanField(default=False, verbose_name='Comment Moderation'),
),
migrations.AlterField(
model_name='project',
name='conf_py_file',
field=models.CharField(blank=True, default='', help_text='Path from project root to <code>conf.py</code> file (ex. <code>docs/conf.py</code>). Leave blank if you want us to find it for you.', max_length=255, verbose_name='Python configuration file'),
),
migrations.AlterField(
model_name='project',
name='has_valid_webhook',
field=models.BooleanField(default=False, help_text='This project has been built with a webhook'),
),
migrations.AlterField(
model_name='project',
name='programming_language',
field=models.CharField(blank=True, choices=[('words', 'Only Words'), ('py', 'Python'), ('js', 'JavaScript'), ('php', 'PHP'), ('ruby', 'Ruby'), ('perl', 'Perl'), ('java', 'Java'), ('go', 'Go'), ('julia', 'Julia'), ('c', 'C'), ('csharp', 'C#'), ('cpp', 'C++'), ('objc', 'Objective-C'), ('css', 'CSS'), ('ts', 'TypeScript'), ('swift', 'Swift'), ('vb', 'Visual Basic'), ('r', 'R'), ('scala', 'Scala'), ('groovy', 'Groovy'), ('coffee', 'CoffeeScript'), ('lua', 'Lua'), ('haskell', 'Haskell'), ('other', 'Other')], default='words', help_text='The primary programming language the project is written in.', max_length=20, verbose_name='Programming Language'),
),
]

View File

@ -21,8 +21,6 @@ from django.utils.translation import ugettext_lazy as _
from django.views.generic import ListView, TemplateView, View
from formtools.wizard.views import SessionWizardView
from vanilla import CreateView, DeleteView, DetailView, GenericView, UpdateView
from readthedocs.bookmarks.models import Bookmark
from readthedocs.builds.forms import AliasForm, VersionForm
from readthedocs.builds.models import Version, VersionAlias
from readthedocs.core.mixins import ListViewWithForm, LoginRequiredMixin
@ -61,13 +59,6 @@ class ProjectDashboard(PrivateViewMixin, ListView):
def get_context_data(self, **kwargs):
context = super(ProjectDashboard, self).get_context_data(**kwargs)
bookmarks = Bookmark.objects.filter(user=self.request.user)
if bookmarks.exists:
context['bookmark_list'] = bookmarks[:3]
else:
bookmarks = None
return context

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.12 on 2018-02-17 11:21
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('redirects', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='redirect',
name='to_url',
field=models.CharField(blank=True, db_index=True, help_text='Absolute or relative URL. Examples: <b>/tutorial/install.html</b>', max_length=255, verbose_name='To URL'),
),
]

View File

@ -87,7 +87,6 @@ class CommunityBaseSettings(Settings):
'tastypie',
# our apps
'readthedocs.bookmarks',
'readthedocs.projects',
'readthedocs.builds',
'readthedocs.comments',

View File

@ -1,14 +0,0 @@
{% extends "projects/base_project.html" %}
{% load i18n %}
{% block title %}{% blocktrans with bookmark.page as name %}Delete {{ name }}?{% endblocktrans %}{% endblock %}
{% block content-header %}<h1>{% blocktrans with bookmark.page as name %}Delete {{ name }}?{% endblocktrans %}</h1>{% endblock %}
{% block content %}
<p>{% trans "You sure?" %} O_o</p>
<form method="post" action=".">{% csrf_token %}
<input type="submit" value="{% trans "Delete forever" %}">
</form>
{% endblock %}

View File

@ -1,30 +0,0 @@
{% extends "base.html" %}
{% load i18n %}
{% load pagination_tags %}
{% block title %}{% trans "Bookmarks" %}{% endblock %}
{% block nav-browse %}class="active"{% endblock %}
{% block content %}
{% autopaginate bookmark_list 15 %}
<!-- BEGIN builds list -->
<div class="module">
<div class="module-wrapper">
<div class="module-header">
<h2>{% trans "All Bookmarks" %}</h2>
</div>
</div>
</div>
<!-- END builds list -->
{% include "core/bookmark_list_detailed.html" %}
{% paginate %}
{% endblock %}

View File

@ -39,7 +39,6 @@ basic_urls = [
]
rtd_urls = [
url(r'^bookmarks/', include('readthedocs.bookmarks.urls')),
url(r'^search/$', search_views.elastic_search, name='search'),
url(r'^dashboard/', include('readthedocs.projects.urls.private')),
url(r'^profiles/', include('readthedocs.profiles.urls.public')),