Skip to content
This repository was archived by the owner on Aug 26, 2024. It is now read-only.

bugfix #315

Merged
merged 17 commits into from
Jul 31, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion gsoc/admin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from .models import (UserProfile, RegLink, UserDetails, Scheduler, PageNotification, AddUserLog,
BlogPostDueDate, Builder, Timeline, ArticleReview, Event, SubOrgDetails,
GsocEndDate, Comment, SendEmail)
GsocEndDate, Comment, SendEmail, BlogPostHistory)
from .forms import (UserProfileForm, UserDetailsForm, RegLinkForm, BlogPostDueDateForm, EventForm,
GsocEndDateForm)

Expand Down Expand Up @@ -368,6 +368,7 @@ def formfield_for_foreignkey(self, db_field, request, **kwargs):
class RegLinkInline(admin.TabularInline):
model = RegLink
form = RegLinkForm
extra = 1


class AddUserLogAdmin(admin.ModelAdmin):
Expand Down Expand Up @@ -544,3 +545,18 @@ def has_change_permission(self, request, obj=None):


admin.site.register(SendEmail, SendEmailAdmin)


class BlogPostHistoryAdmin(admin.ModelAdmin):
list_display = ('article', 'timestamp')
list_filter = ('article', )
fields = ('article', 'content_safe', 'timestamp')

def has_change_permission(self, request, obj=None):
return False

def content_safe(self, obj):
return mark_safe(obj.content)


admin.site.register(BlogPostHistory, BlogPostHistoryAdmin)
34 changes: 28 additions & 6 deletions gsoc/cms_toolbars.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,34 @@ def add_admin_menu(self):
if user and user.is_superuser:
self._admin_menu.add_sideframe_item(_('Schedulers'),
url=admin_reverse('gsoc_scheduler_changelist'))
self._admin_menu.add_break(ADMINISTRATION_BREAK)

# cms users settings
self._admin_menu.add_sideframe_item(_('User settings'), url=admin_reverse('cms_usersettings_change'))
self._admin_menu.add_break(USER_SETTINGS_BREAK)
if user and user.is_superuser:
self._admin_menu.add_sideframe_item(_('Builders'),
url=admin_reverse('gsoc_builder_changelist'))
self._admin_menu.add_sideframe_item(_('Review Article'),
url=admin_reverse('gsoc_articlereview_changelist'))
self._admin_menu.add_sideframe_item(_('Timeline'),
url=admin_reverse('gsoc_timeline_changelist'))
self._admin_menu.add_sideframe_item(_('Send Email'),
url=admin_reverse('gsoc_sendemail_add'))
self._admin_menu.add_sideframe_item(_('Suborg Applications'),
url=admin_reverse('gsoc_suborgdetails_changelist'))
self._admin_menu.add_modal_item(
name='Add Users',
url=admin_reverse('gsoc_adduserlog_add'),
on_close=None,
)

if user:
self._admin_menu.add_link_item(_('New Suborg Application'),
reverse('suborg:register_suborg'))
self._admin_menu.add_link_item(_('Manage Suborg Application'),
reverse('suborg:application_list'))

self._admin_menu.add_break(ADMINISTRATION_BREAK)

# cms users settings
self._admin_menu.add_sideframe_item(_('User settings'),
url=admin_reverse('cms_usersettings_change'))
self._admin_menu.add_break(USER_SETTINGS_BREAK)
# clipboard
if self.toolbar.edit_mode_active:
# True if the clipboard exists and there's plugins in it.
Expand Down Expand Up @@ -226,5 +243,10 @@ def populate(self):
except ArticleReview.DoesNotExist:
pass

if user.is_superuser:
url = (f"{admin_reverse('gsoc_blogposthistory_changelist')}"
f"?article__id__exact={article.id}")
self.toolbar.add_sideframe_item(_('View History'), url=url)


NewsBlogToolbar.populate = populate
50 changes: 50 additions & 0 deletions gsoc/common/utils/memcached_stats.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import re
import telnetlib
import sys


class MemcachedStats:

_client = None
_key_regex = re.compile(r'ITEM (.*) \[(.*); (.*)\]')
_slab_regex = re.compile(r'STAT items:(.*):number')
_stat_regex = re.compile(r"STAT (.*) (.*)\r")

def __init__(self, host='localhost', port='11211', timeout=None):
self._host = host
self._port = port
self._timeout = timeout

@property
def client(self):
if self._client is None:
self._client = telnetlib.Telnet(self._host, self._port,
self._timeout)
return self._client

def command(self, cmd):
' Write a command to telnet and return the response '
self.client.write(("%s\n" % cmd).encode('ascii'))
return self.client.read_until(b'END').decode('ascii')

def key_details(self, sort=True, limit=100):
' Return a list of tuples containing keys and details '
cmd = 'stats cachedump %s %s'
keys = [key for id in self.slab_ids()
for key in self._key_regex.findall(self.command(cmd % (id, limit)))]
if sort:
return sorted(keys)
else:
return keys

def keys(self, sort=True, limit=100):
' Return a list of keys in use '
return [key[0] for key in self.key_details(sort=sort, limit=limit)]

def slab_ids(self):
' Return a list of slab ids in use '
return self._slab_regex.findall(self.command('stats items'))

def stats(self):
' Return a dict containing memcached stats '
return dict(self._stat_regex.findall(self.command('stats')))
11 changes: 9 additions & 2 deletions gsoc/common/utils/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,23 +85,30 @@ def is_year(file_name):
return False


def get_files(repo, except_files=['CNAME', 'LICENSE.md', 'README.md']):
def get_files(repo, except_files=['CNAME', 'LICENSE.md', 'README.md', 'favicon.ico', 'robots.txt']):
contents = repo.get_contents('')
files = []
while contents:
file_content = contents.pop(0)
if not (file_content.path in except_files or is_year(file_content.path)):
if file_content.type == "dir":
if file_content.type == 'dir':
contents.extend(repo.get_contents(file_content.path))
else:
files.append(file_content)
return files


def update_robots_file(repo, current_year):
c = repo.get_contents('robots.txt')
new_content = c.decoded_content.strip() + f'\nDisallow: /{current_year}/\n'.encode()
repo.update_file(c.path, 'Update robots.txt', new_content, c.sha)


def archive_current_gsoc_files(current_year):
g = Github(settings.GITHUB_ACCESS_TOKEN)
repo = g.get_repo(settings.STATIC_SITE_REPO)
files = get_files(repo)
update_robots_file(repo, current_year)
for file in files:
try:
repo.create_file(f'{current_year}/{file.path}',
Expand Down
24 changes: 24 additions & 0 deletions gsoc/migrations/0049_blogposthistory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 2.1.10 on 2019-07-28 09:57

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('aldryn_newsblog', '0016_auto_20180329_1417'),
('gsoc', '0048_reglink_send_notifications'),
]

operations = [
migrations.CreateModel(
name='BlogPostHistory',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('timestamp', models.DateTimeField(auto_now_add=True)),
('content', models.TextField(blank=True, null=True)),
('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='aldryn_newsblog.Article')),
],
),
]
65 changes: 32 additions & 33 deletions gsoc/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ def gen_uuid_str():
NewsBlogConfig.__str__ = lambda self: self.app_title


def current_year_profile(self):
gsoc_year = GsocYear.objects.first()
profile = self.userprofile_set.filter(gsoc_year=gsoc_year, role__in=[1, 2, 3])
return profile.first() if len(profile) > 0 else None


auth.models.User.add_to_class('current_year_profile', current_year_profile)


def has_proposal(self):
try:
proposal = self.student_profile().accepted_proposal_pdf
Expand Down Expand Up @@ -112,34 +121,6 @@ def get_root_comments(self):
Article.add_to_class('get_root_comments', get_root_comments)


def is_unclean(self):
unclean_texts = (
'<pre>',
'</pre>',
'&lt;',
'&gt;',
)
for _ in unclean_texts:
if _ in self.lead_in:
return True
return False


Article.add_to_class('is_unclean', is_unclean)


def clean_article_html(self):
self.lead_in = re.sub(r'<pre>', '<code>', self.lead_in)
self.lead_in = re.sub(r'<\/pre>', '</code>', self.lead_in)
self.lead_in = re.sub(r'&lt;', '<', self.lead_in)
self.lead_in = re.sub(r'&gt;', '>', self.lead_in)
self.lead_in = mark_safe(self.lead_in)
self.save()


Article.add_to_class('clean_article_html', clean_article_html)


# Models

class SubOrg(models.Model):
Expand Down Expand Up @@ -488,6 +469,12 @@ def save(self, *args, **kwargs):
super().save(*args, **kwargs)


class BlogPostHistory(models.Model):
article = models.ForeignKey(Article, on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_now_add=True)
content = models.TextField(null=True, blank=True)


class BlogPostDueDate(models.Model):
categories = (
(0, 'Weekly Check-In'),
Expand Down Expand Up @@ -1098,11 +1085,17 @@ def decrease_blog_counter(sender, instance, **kwargs):
up.save()


# Clean lead_in HTML when new Article is created
# @receiver(models.signals.post_save, sender=Article)
# def clean_html(sender, instance, **kwargs):
# if instance.is_unclean():
# instance.clean_article_html()
# Add ArticleReveiw object when new Article is created
@receiver(models.signals.post_save, sender=Article)
def add_review(sender, instance, **kwargs):
ar = ArticleReview.objects.filter(article=instance).all()
if not ar:
ArticleReview.objects.create(article=instance)

if ar:
ar = ar.first()
ar.is_reviewed = False
ar.save()


# Add ArticleReveiw object when new Article is created
Expand All @@ -1116,3 +1109,9 @@ def add_review(sender, instance, **kwargs):
ar = ar.first()
ar.is_reviewed = False
ar.save()


# Add BlogPostHistory object when new Article is created
@receiver(models.signals.post_save, sender=Article)
def add_history(sender, instance, **kwargs):
BlogPostHistory.objects.create(article=instance, content=instance.lead_in)
62 changes: 62 additions & 0 deletions gsoc/static/css/article.css
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,65 @@ article > heading {
text-decoration: none;
color: white;
}

.aldryn-newsblog-comments {
margin: 16px 0;
padding: 16px 24px;
}

.aldryn-newsblog-comments form {
display: none;
}

.aldryn-newsblog-comments #form-root {
display: block;
}

.aldryn-newsblog-subcomments {
padding-left: 24px;
border-left: 0.1px solid #eee;
}

.comment {
padding: 5px 10px;
margin: 5px 0px;
background: #eee;
}

.comment.selected {
background: #ccc;
}

.comment-container .c-username {
color: #489EBA;
font-size: 12px;
font-weight: bold;
}

.comment-container .c-actions {
font-size: 12px;
}

.comment-container .c-actions span {
margin-right: 10px;
}

.comment-container .c-actions .reply {
cursor: pointer;
}

.comment-container .c-actions .share {
cursor: pointer;
}

.comment-container .c-actions .delete {
cursor: pointer;
}

.comment-container .c-content {
font-size: 14px;
}

form textarea {
border-radius: 0 0 4px 4px !important;
}
Loading