Kaydet (Commit) 8912788b authored tarafından Batuhan Taşkaya's avatar Batuhan Taşkaya

Link previewing, link feeding and more on

üst 6f262d48
......@@ -2,15 +2,18 @@ from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
from social.forms import SocialUserCreationForm, SocialUserChangeForm
from social.models import SocialUser, Post, Snippet
from social.forms import SocialUserChangeForm, SocialUserCreationForm
from social.models import Link, Post, Snippet, SocialUser
class SocialUserAdmin(UserAdmin):
add_form = SocialUserCreationForm
form = SocialUserChangeForm
model = SocialUser
list_display = ['email', 'username',]
list_display = ["email", "username"]
admin.site.register(SocialUser, SocialUserAdmin)
admin.site.register(Post)
admin.site.register(Snippet)
admin.site.register(Link)
......@@ -2,4 +2,4 @@ from django.apps import AppConfig
class SocialConfig(AppConfig):
name = 'social'
name = "social"
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
from social.models import SocialUser
class SocialUserCreationForm(UserCreationForm):
class SocialUserCreationForm(UserCreationForm):
class Meta(UserCreationForm):
model = SocialUser
fields = ('username', 'email')
fields = ("username", "email")
class SocialUserChangeForm(UserChangeForm):
class SocialUserChangeForm(UserChangeForm):
class Meta:
model = SocialUser
fields = ('username', 'email')
fields = ("username", "email")
# Generated by Django 2.2.1 on 2019-05-04 17:18
from django.conf import settings
import django.contrib.auth.models
import django.contrib.auth.validators
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0011_update_proxy_permissions'),
]
dependencies = [("auth", "0011_update_proxy_permissions")]
operations = [
migrations.CreateModel(
name='SocialUser',
name="SocialUser",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("password", models.CharField(max_length=128, verbose_name="password")),
(
"last_login",
models.DateTimeField(
blank=True, null=True, verbose_name="last login"
),
),
(
"is_superuser",
models.BooleanField(
default=False,
help_text="Designates that this user has all permissions without explicitly assigning them.",
verbose_name="superuser status",
),
),
(
"username",
models.CharField(
error_messages={
"unique": "A user with that username already exists."
},
help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
max_length=150,
unique=True,
validators=[
django.contrib.auth.validators.UnicodeUsernameValidator()
],
verbose_name="username",
),
),
(
"first_name",
models.CharField(
blank=True, max_length=30, verbose_name="first name"
),
),
(
"last_name",
models.CharField(
blank=True, max_length=150, verbose_name="last name"
),
),
(
"email",
models.EmailField(
blank=True, max_length=254, verbose_name="email address"
),
),
(
"is_staff",
models.BooleanField(
default=False,
help_text="Designates whether the user can log into this admin site.",
verbose_name="staff status",
),
),
(
"is_active",
models.BooleanField(
default=True,
help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
verbose_name="active",
),
),
(
"date_joined",
models.DateTimeField(
default=django.utils.timezone.now, verbose_name="date joined"
),
),
(
"groups",
models.ManyToManyField(
blank=True,
help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
related_name="user_set",
related_query_name="user",
to="auth.Group",
verbose_name="groups",
),
),
(
"user_permissions",
models.ManyToManyField(
blank=True,
help_text="Specific permissions for this user.",
related_name="user_set",
related_query_name="user",
to="auth.Permission",
verbose_name="user permissions",
),
),
],
options={
'verbose_name': 'user',
'verbose_name_plural': 'users',
'abstract': False,
"verbose_name": "user",
"verbose_name_plural": "users",
"abstract": False,
},
managers=[
('objects', django.contrib.auth.models.UserManager()),
],
managers=[("objects", django.contrib.auth.models.UserManager())],
),
migrations.CreateModel(
name='Sharable',
name="Sharable",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('pub_date', models.TimeField(auto_now=True)),
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("pub_date", models.TimeField(auto_now=True)),
(
"author",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
options={
'ordering': ['pub_date'],
},
options={"ordering": ["pub_date"]},
),
migrations.CreateModel(
name='Post',
name="Post",
fields=[
('sharable_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='social.Sharable')),
('text', models.TextField(max_length=288)),
(
"sharable_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="social.Sharable",
),
),
("text", models.TextField(max_length=288)),
],
bases=('social.sharable',),
bases=("social.sharable",),
),
]
# Generated by Django 2.2.1 on 2019-05-04 17:26
from django.db import migrations, models
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('social', '0001_initial'),
]
dependencies = [("social", "0001_initial")]
operations = [
migrations.CreateModel(
name='Snippet',
name="Snippet",
fields=[
('sharable_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='social.Sharable')),
('text', models.TextField()),
(
"sharable_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="social.Sharable",
),
),
("text", models.TextField()),
],
bases=('social.sharable',),
),
bases=("social.sharable",),
)
]
......@@ -5,14 +5,15 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('social', '0002_snippet'),
]
dependencies = [("social", "0002_snippet")]
operations = [
migrations.AddField(
model_name='socialuser',
name='avatar',
field=models.URLField(blank=True, default='http://www.iconarchive.com/download/i106224/papirus-team/papirus-apps/python.ico'),
),
model_name="socialuser",
name="avatar",
field=models.URLField(
blank=True,
default="http://www.iconarchive.com/download/i106224/papirus-team/papirus-apps/python.ico",
),
)
]
# Generated by Django 2.2.1 on 2019-05-05 11:42
from django.db import migrations, models
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('social', '0003_socialuser_avatar'),
]
dependencies = [("social", "0003_socialuser_avatar")]
operations = [
migrations.CreateModel(
name='Link',
name="Link",
fields=[
('sharable_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='social.Sharable')),
('url', models.URLField()),
(
"sharable_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="social.Sharable",
),
),
("url", models.URLField()),
],
bases=('social.sharable',),
),
bases=("social.sharable",),
)
]
from django.db import models
from django.conf import settings
from django.contrib.auth.models import AbstractUser
from django.db import models
class SocialUser(AbstractUser):
avatar = models.URLField(blank=True, default=settings.AVATAR)
@property
def slug(self):
return self.username
class Sharable(models.Model):
class Meta:
ordering = ['pub_date']
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
ordering = ["pub_date"]
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
pub_date = models.TimeField(auto_now=True)
def __str__(self):
return f"{self.__class__.__name__}@{self.author}"
class Post(Sharable):
text = models.TextField(max_length=settings.MAX_POST_LENGTH)
class Snippet(Sharable):
text = models.TextField()
class Link(Sharable):
url = models.URLField()
......@@ -3,6 +3,32 @@
<head>
<meta charset="utf-8">
<title>{% block title %}Aspava{% endblock %}</title>
<style>
.col-1 {width: 8.33%;}
.col-2 {width: 16.66%;}
.col-3 {width: 25%;}
.col-4 {width: 33.33%;}
.col-5 {width: 41.66%;}
.col-6 {width: 50%;}
.col-7 {width: 58.33%;}
.col-8 {width: 66.66%;}
.col-9 {width: 75%;}
.col-10 {width: 83.33%;}
.col-11 {width: 91.66%;}
.col-12 {width: 100%;}
.row::after {
content: "";
clear: both;
display: table;
}
[class*="col-"] {
float: left;
padding: 15px;
border: 1px solid red;
}
</style>
{% block css %}{% endblock %}
</head>
<body>
......
......@@ -11,7 +11,7 @@
<p><a href="{% url 'logout' %}">logout</a></p>
{% load renderer %}
{% for item in feed %}
<div>
<div class="{{ item | get_class }}">
<fieldset>
<legend><a href="{% url 'profile' item.author %}">{{ item.author }}</a></legend>
{% as_html item %}
......
{% load renderer %}
{% autoescape off %}
{% get_preview item.url %}
{% endautoescape %}
from contextlib import contextmanager
from html.parser import HTMLParser
from io import StringIO
from urllib.request import urlopen
from django import template
from django.template.loader import render_to_string
register = template.Library()
@register.filter
def get_class(item):
return item.__class__.__name__.lower()
@register.simple_tag
def as_html(item):
result = render_to_string(f"repr/{item.__class__.__name__.lower()}.html", {'item': item})
return result
result = render_to_string(
f"repr/{item.__class__.__name__.lower()}.html", {"item": item}
)
return result
class MetaParser(HTMLParser):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._meta = {}
def handle_starttag(self, tag, attrs):
attrs = dict(attrs)
if tag == "meta" and attrs.get("property", "").startswith("og:"):
self._meta[attrs["property"].strip("og:")] = attrs.get("content")
class SimpleHTMLConstructor:
def __init__(self):
self._buffer = StringIO()
self._indent = 0
def nl(self):
self._buffer.write("\n")
self._buffer.write(" " * 4 * self._indent)
def write(self, *text):
self._buffer.write("".join(text))
self.nl()
def ctx(self, *args, **kwds):
with self.tag(*args, **kwds):
pass
@contextmanager
def tag(self, tag, close=True, **attrs):
attrs = self._strip_attrs(attrs)
try:
self._buffer.write(f"<{tag}")
for attr, value in attrs.items():
self._buffer.write(f" {attr}='{value}'")
self._buffer.write(">")
self._indent += 1
self.nl()
yield
finally:
self._indent -= 1
self.nl()
if close:
self._buffer.write(f"</{tag}>")
@staticmethod
def _strip_attrs(attrs):
if "cls" in attrs:
attrs["class"] = attrs.pop("cls")
return attrs
def __str__(self):
return self._buffer.getvalue()
def construct_preview(meta):
html = SimpleHTMLConstructor()
with html.tag("div", cls="row"):
with html.tag("div", cls="col-3"):
html.ctx("img", close=False, src=meta["image"], alt=meta.get("title"))
with html.tag("div", cls="col-9"):
if meta.get("title"):
with html.tag("h3"):
html.write(meta["title"], " ", meta.get("site_name"))
html.ctx("br", close=False)
if meta.get("description"):
with html.tag("p"):
html.write(meta["description"])
return html
@register.simple_tag
def get_preview(url):
parser = MetaParser()
with urlopen(url) as conn:
headers = conn.info()
parser.feed(conn.read().decode())
return construct_preview(parser._meta)
from collections import UserList
from dataclasses import dataclass
from typing import Optional, Sequence
from django.urls import include, path
from social.views import Home, Register, Profile
from social.views import Home, Profile, Register
@dataclass(frozen=True, unsafe_hash=True)
......@@ -13,7 +15,8 @@ class IncludeFilter:
def __str__(self):
return self.module
class PatternManager:
"""A pattern manager for urlpatterns.
......@@ -36,7 +39,7 @@ class PatternManager:
<path.n>: <include.n>,
'accounts': 'django.contrib.auth.urls'}
"""
def __init__(self):
self.data = []
patterns = dict(
......@@ -61,20 +64,18 @@ class PatternManager:
pattern = path(route, view, name=name)
self.data.append(pattern)
def _filtered_include(self, module, included):
urlconf_module, *meta = included
urlpatterns = urlconf_module.urlpatterns
_type = type(urlpatterns)
if module.blacklist:
urlpatterns = filter(
lambda pattern: pattern.name not in module.blacklist,
urlpatterns,
lambda pattern: pattern.name not in module.blacklist, urlpatterns
)
if module.whitelist:
urlpatterns = filter(
lambda pattern: pattern.name in module.whitelist,
urlpatterns,
lambda pattern: pattern.name in module.whitelist, urlpatterns
)
urlconf_module.urlpatterns = _type(urlpatterns)
......@@ -86,7 +87,7 @@ class SocialPatterns(PatternManager, UserList):
home = "", Home
profile = "people/<slug>/", Profile
register = "accounts/register/", Register
includes = {
"accounts": IncludeFilter(
"django.contrib.auth.urls", whitelist=("login", "logout")
......
from itertools import chain
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm
from django.urls import reverse_lazy
from django.views.generic import CreateView, ListView, DetailView
from django.views.generic import CreateView, DetailView, ListView
from django.views.generic.base import TemplateView
from social.models import Post, Snippet
from django.contrib.auth import get_user_model
from social.models import Link, Post, Snippet
class ExtendedListView(ListView):
def get_queryset(self):
return chain.from_iterable(map(lambda model: model._default_manager.all(), self.models))
return chain.from_iterable(
map(lambda model: model._default_manager.all(), self.models)
)
class Home(ExtendedListView):
models = Post, Snippet
template_name = 'home.html'
context_object_name = 'feed'
models = Post, Snippet, Link
template_name = "home.html"
context_object_name = "feed"
def get_queryset(self):
qs = list(super().get_queryset())
qs.sort(key = (lambda item: item.pub_date))
qs.sort(key=(lambda item: item.pub_date))
return qs
class Register(CreateView):
form_class = UserCreationForm
success_url = reverse_lazy('login')
template_name = 'registration/register.html'
success_url = reverse_lazy("login")
template_name = "registration/register.html"
class Profile(DetailView):
model = get_user_model()
slug_field = 'username'
template_name = 'user/profile.html'
slug_field = "username"
template_name = "user/profile.html"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment