Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

0.0.1

  • Loading branch information...
commit 098e4ddf1b65d31da05df41e82d54a2cd34b170c 1 parent bae1e63
Roman Gladkov authored
1  .gitignore
... ...
@@ -1,2 +1,3 @@
1 1
 *.pyc
2 2
 lulz.db
  3
+public/media/backgrounds/*.*
3  decorators.py
... ...
@@ -1,6 +1,5 @@
1 1
 # -*- coding: utf-8 -*-
2 2
 from functools import wraps
3  
-import datetime
4 3
 from django.http import HttpResponse
5 4
 from django.shortcuts import render_to_response
6 5
 from django.template import RequestContext
@@ -27,6 +26,7 @@ def wrapper(request, *args, **kwargs):
27 26
         return wrapper
28 27
     return renderer
29 28
 
  29
+
30 30
 def render_json(func):
31 31
     """Decorator for rendering data as json"""
32 32
     def wrap(request, *args, **kwargs):
@@ -38,4 +38,3 @@ def wrap(request, *args, **kwargs):
38 38
             pass
39 39
         return HttpResponse(dumps(response), mimetype="application/json")
40 40
     return wrap
41  
-  
15  lulz/admin.py
... ...
@@ -1,10 +1,14 @@
1 1
 from django.contrib import admin
2 2
 from django.contrib.auth.models import Group
3  
-from models import Category, Comments, Job, Likes
  3
+from models import Category, Comments, Job, Likes, Image
  4
+
  5
+
  6
+class AdminImages(admin.ModelAdmin):
  7
+    list_display = ("name", "image",)
4 8
 
5 9
 
6 10
 class AdminJobs(admin.ModelAdmin):
7  
-    list_display = ("name", "date", "published")
  11
+    list_display = ("name", "category", "published", "date")
8 12
 
9 13
 
10 14
 class AdminCategory(admin.ModelAdmin):
@@ -12,13 +16,16 @@ class AdminCategory(admin.ModelAdmin):
12 16
 
13 17
 
14 18
 class AdminComments(admin.ModelAdmin):
15  
-    list_display = ("text", "job")
  19
+    list_display = ("text", "job", "ip", "agent")
  20
+
16 21
 
17 22
 class AdminLikes(admin.ModelAdmin):
18 23
     list_display = ("ip", "type")
19 24
 
  25
+
  26
+admin.site.register(Image, AdminImages)
20 27
 admin.site.register(Category, AdminCategory)
21 28
 admin.site.register(Comments, AdminComments)
22 29
 admin.site.register(Job, AdminJobs)
23 30
 admin.site.register(Likes, AdminLikes)
24  
-admin.site.unregister(Group)
  31
+admin.site.unregister(Group)
10  lulz/forms.py
@@ -12,14 +12,20 @@ class Meta:
12 12
             "desc": forms.Textarea(attrs={"class": "required"}),
13 13
             "tags": forms.TextInput(attrs={"class": "required"}),
14 14
             "link": forms.TextInput(attrs={"class": "required url"}),
15  
-            "cateogry": forms.CheckboxInput(attrs={"class": "required digits"}),
  15
+            "cateogry": forms.CheckboxInput(
  16
+                attrs={"class": "required digits"}
  17
+            ),
16 18
         }
17 19
 
18 20
 
19 21
 class AddComment(forms.ModelForm):
20 22
     class Meta:
21 23
         model = Comments
22  
-        fields = ("text",)
  24
+        fields = ("text", "job")
  25
+        widgets = {
  26
+            "text": forms.Textarea(attrs={"class": "required"}),
  27
+            "job": forms.HiddenInput()
  28
+        }
23 29
 
24 30
 
25 31
 class SearchForm(forms.Form):
29  lulz/models.py
@@ -2,12 +2,27 @@
2 2
 from django.db import models
3 3
 
4 4
 
  5
+class Image(models.Model):
  6
+    name = models.CharField(max_length=100,
  7
+                            verbose_name=u"Название")
  8
+    image = models.ImageField(upload_to='backgrounds',
  9
+                                  verbose_name=u"Фон")
  10
+
  11
+    class Meta:
  12
+        verbose_name = u"Изображение"
  13
+        verbose_name_plural = u"Изображения"
  14
+
  15
+    def __unicode__(self):
  16
+        return self.name
  17
+
  18
+
5 19
 class Category(models.Model):
6 20
     name = models.CharField(max_length=100,
7 21
                             blank=False,
8 22
                             verbose_name=u"Название")
9  
-    image = models.ImageField(upload_to='backgrounds',
10  
-                              verbose_name=u"Фон")
  23
+    image = models.ManyToManyField(Image,
  24
+                                   related_name="catimages",
  25
+                                   verbose_name=u"Фон")
11 26
 
12 27
     class Meta:
13 28
         verbose_name = u"Категория"
@@ -28,7 +43,7 @@ class Job(models.Model):
28 43
     link = models.URLField(max_length=100,
29 44
                             verbose_name=u"Ссылка на оригинал")
30 45
     published = models.BooleanField(default=False,
31  
-                                    verbose_name=u"Оубликовано")
  46
+                                    verbose_name=u"Опубликовано")
32 47
     date = models.DateTimeField(auto_now=True,
33 48
                                 verbose_name=u"Дата публикации")
34 49
     category = models.ForeignKey(Category,
@@ -38,7 +53,6 @@ class Job(models.Model):
38 53
                                       blank=True,
39 54
                                       verbose_name=u"Комментарии")
40 55
 
41  
-
42 56
     class Meta:
43 57
         verbose_name = u"Вакансия"
44 58
         verbose_name_plural = u"Вакансии"
@@ -53,6 +67,8 @@ class Comments(models.Model):
53 67
     job = models.ForeignKey(Job,
54 68
                             related_name='jobcomm',
55 69
                             verbose_name=u"Вакансия")
  70
+    agent = models.CharField(max_length=200, verbose_name=u"User-Agent")
  71
+    ip = models.CharField(max_length=100, verbose_name=u"IP")
56 72
 
57 73
     class Meta:
58 74
         verbose_name = u"Комментарий"
@@ -67,7 +83,9 @@ class Likes(models.Model):
67 83
         ('1', '+'),
68 84
         ('0', '-')
69 85
     )
70  
-    job = models.ForeignKey(Job, related_name='joblikes', verbose_name=u"Вакансия")
  86
+    job = models.ForeignKey(Job,
  87
+                            related_name='joblikes',
  88
+                            verbose_name=u"Вакансия")
71 89
     agent = models.CharField(max_length=200, verbose_name=u"User-Agent")
72 90
     ip = models.CharField(max_length=100, verbose_name=u"IP")
73 91
     type = models.BooleanField(choices=CHOISES, verbose_name=u"Тип")
@@ -78,4 +96,3 @@ class Meta:
78 96
 
79 97
     def __unicode__(self):
80 98
         return '%s/%s' % (self.job.name, self.type)
81  
-
2  lulz/templatetags/__init__.py
... ...
@@ -1,2 +0,0 @@
1  
-__author__ = 'd1ffuz0r'
2  
-  
18  lulz/templatetags/forms.py
... ...
@@ -1,18 +0,0 @@
1  
-from django import template
2  
-from lulz.forms import AddJob, AddComment, SearchForm
3  
-register = template.Library()
4  
-
5  
-
6  
-@register.simple_tag()
7  
-def addjob():
8  
-    return AddJob()
9  
-
10  
-
11  
-@register.simple_tag()
12  
-def addcomment():
13  
-    return AddComment().as_p()
14  
-
15  
-
16  
-@register.simple_tag()
17  
-def search():
18  
-    return SearchForm()
104  lulz/tests.py
... ...
@@ -1,45 +1,127 @@
1 1
 # -*- coding: utf-8 -*-
2 2
 from django.test import TestCase
  3
+from unittest import skip
3 4
 from django.test.client import Client
  5
+from lulz.models import Image
4 6
 from models import Job, Category, Comments, Likes
5 7
 
6 8
 
7 9
 class ViewsTests(TestCase):
8 10
     def setUp(self):
  11
+        self.category = Category.objects.create(name="php")
9 12
         self.client = Client()
10 13
 
11 14
     def test_home(self):
12  
-        request = self.client.get('/')
13  
-        self.assertContains(request, text='Нет работ')
  15
+        request = self.client.get("/")
  16
+        self.assertContains(request, text="ДЖОПЛУЛЗ")
14 17
 
15 18
     def test_admin(self):
16  
-        request = self.client.get('/admin/')
17  
-        self.assertContains(request, text='Django')
  19
+        request = self.client.get("/admin/")
  20
+        self.assertContains(request, text="Django")
  21
+
  22
+    def test_full_vacancy_get_fail(self):
  23
+        request = self.client.get("/ajax/full/")
  24
+        self.assertEqual(request.content, '{"success": false}')
  25
+
  26
+    def test_full_vacancy_ajax_true(self):
  27
+        self.image = Image.objects.create(name="phpp",
  28
+                                          image="img/php.png")
  29
+
  30
+        category = Category.objects.create(name="php")
  31
+        category.image.add(self.image)
  32
+        self.job = Job.objects.create(name="test",
  33
+                                      desc="description",
  34
+                                      category=category,
  35
+                                      published=True)
  36
+        self.comment = Comments.objects.create(text="lol",
  37
+                                               job=self.job)
  38
+        request = self.client.post("/ajax/full/", data={
  39
+            "id": self.job.id
  40
+        })
  41
+        self.assertContains(request, "vacancy")
  42
+
  43
+    def test_create_comment_get_false(self):
  44
+        request = self.client.get("/ajax/addcomment/")
  45
+        self.assertEqual(request.content, '{"success": false}')
  46
+
  47
+    @skip("working")
  48
+    def test_create_comment_ajax_true(self):
  49
+        self.image = Image.objects.create(name="phpp",
  50
+                                          image="img/php.png")
  51
+        category = Category.objects.create(name="php", image=[1])
  52
+        Job.objects.create(name="test",
  53
+                           desc="description",
  54
+                           category=category)
  55
+        print self.job.id
  56
+        request = self.client.post("/ajax/addcomment/", data={
  57
+            "text": "test",
  58
+            "job": 1
  59
+        })
  60
+        self.assertEqual(request.content, '{"success": true}')
  61
+
  62
+    def test_create_comment_ajax_false(self):
  63
+        request = self.client.post("/ajax/addcomment/", data={
  64
+            "text": "test"
  65
+        })
  66
+        self.assertEqual(request.content, '{"success": false}')
  67
+
  68
+    def test_create_vacancy_get_false(self):
  69
+        request = self.client.get("/ajax/addvacancy/")
  70
+        self.assertEqual(request.content, '{"success": false}')
  71
+
  72
+    def test_create_vacancy_ajax_true(self):
  73
+        request = self.client.post("/ajax/addvacancy/", data={
  74
+            "name": "test",
  75
+            "desc": "testdesc",
  76
+            "tags": "test, test1, test2",
  77
+            "category": 1,
  78
+            "link": "http://google.com"
  79
+        })
  80
+        self.assertEqual(request.content, '{"success": true}')
  81
+
  82
+    def test_create_vacancy_ajax_false(self):
  83
+        request = self.client.post("/ajax/addvacancy/", data={
  84
+            "name": "test",
  85
+            "desc": "testdesc",
  86
+            "tags": "test, test1, test2",
  87
+            "category": 1,
  88
+        })
  89
+        self.assertEqual(request.content, '{"success": false}')
  90
+
18 91
 
19 92
 class ModelsTest(TestCase):
20 93
     def setUp(self):
21  
-        self.category = Category.objects.create(name="php",
22  
-                                      image="php.png")
  94
+        self.image = Image.objects.create(name="phpp",
  95
+                                          image="img/php.png")
  96
+
  97
+        self.category = Category.objects.create(name="php")
  98
+
23 99
         self.job = Job.objects.create(name="test",
24 100
                                       desc="description",
25 101
                                       category=self.category)
  102
+
26 103
         self.comment = Comments.objects.create(text="lol",
27  
-                                              job=self.job)
  104
+                                               job=self.job)
  105
+
28 106
         self.like = Likes.objects.create(job=self.job,
29 107
                                          type="1")
30 108
 
31 109
     def test_job(self):
32 110
         job = Job.objects.filter(name="test").get()
33  
-        self.assertEqual(job.__unicode__(), 'test')
  111
+        self.assertEqual(job.__unicode__(), "test")
34 112
 
35 113
     def test_category(self):
36 114
         cat = Category.objects.filter(name="php").get()
37  
-        self.assertEqual(cat.__unicode__(), 'php')
  115
+        self.assertEqual(cat.__unicode__(), "php")
38 116
 
39 117
     def test_comment(self):
40 118
         comm = Comments.objects.filter(text="lol").get()
41  
-        self.assertEqual(comm.__unicode__(), 'lol/test')
  119
+        self.assertEqual(comm.__unicode__(), "lol/test")
42 120
 
43 121
     def test_like(self):
44 122
         like = Likes.objects.filter(job=self.job).get()
45  
-        self.assertEqual(like.__unicode__(), 'test/True')
  123
+        self.assertEqual(like.__unicode__(), "test/True")
  124
+
  125
+    def test_image(self):
  126
+        image = Image.objects.filter(name="phpp").get()
  127
+        self.assertEqual(image.__unicode__(), "phpp")
158  lulz/views.py
... ...
@@ -1,26 +1,154 @@
1  
-from decorators import render_json
2  
-from forms import AddJob
3  
-from models import Job
  1
+# -*- coding: utf-8 -*-
  2
+from decorators import render_json, render_to
  3
+from lulz.forms import AddJob, AddComment, SearchForm
  4
+from models import Job, Comments, Category, Likes
  5
+
  6
+
  7
+escape = lambda string: string.replace("&", "&").\
  8
+                               replace("<", "&lt;").\
  9
+                               replace(">", "&gt;")
  10
+
  11
+
  12
+@render_to("jobs.html")
  13
+def home(request):
  14
+    count = Job.objects.filter(published=True).count()
  15
+    jobs = Job.objects.filter(published=True).order_by("-id").all()
  16
+    categories = Category.objects.all()
  17
+
  18
+    return {"count": count,
  19
+            "jobs": jobs,
  20
+            "categories": categories,
  21
+            "addjob": AddJob,
  22
+            "addcomment": AddComment,
  23
+            "search": SearchForm}
  24
+
  25
+
  26
+@render_json
  27
+def fetch(request):
  28
+    result = {"success": False, "jobs": []}
  29
+
  30
+    if request.POST and request.POST["cat"]:
  31
+        id = int(request.POST["cat"])
  32
+
  33
+        if id == 900009:
  34
+            jobs_pre = Job.objects.filter(
  35
+                published=True
  36
+            ).order_by("-id").all()
  37
+        else:
  38
+            jobs_pre = Job.objects.filter(
  39
+                published=True,
  40
+                category__id=id
  41
+            ).order_by("-id").all()
  42
+
  43
+        for job in jobs_pre:
  44
+            result["jobs"].append({"id": job.id,
  45
+                                   "name": job.name,
  46
+                                   "desc": escape(job.desc),
  47
+                                   "tags": job.tags,
  48
+                                   "likes": job.likes,
  49
+                                   "link": job.link,
  50
+                                   "date": job.date.__str__(),
  51
+                                   "comments": job.jobcomm.count(),
  52
+                                   "category": job.category.id})
  53
+
  54
+        result["success"] = True
  55
+    return result
  56
+
4 57
 
5 58
 @render_json
6 59
 def addvacancy(request):
7  
-    form = AddJob(request.POST)
8  
-    if form.is_valid():
9  
-        form.save()
10  
-        return {"success": True}
  60
+    result = {"success": False}
  61
+    if request.POST:
  62
+        form = AddJob(request.POST)
  63
+        if form.is_valid():
  64
+            form.save()
  65
+            return {"success": True}
  66
+        else:
  67
+            return result
11 68
     else:
12  
-        return {"success": False}
  69
+        return result
  70
+
  71
+
  72
+@render_json
  73
+def addcomment(request):
  74
+    result = {"success": False}
  75
+    if request.POST:
  76
+        form = AddComment(request.POST)
  77
+        if form.is_valid():
  78
+
  79
+            f = form.save(commit=False)
  80
+            f.agent = request.META["HTTP_USER_AGENT"]
  81
+            f.ip = request.META["REMOTE_ADDR"]
  82
+            f.save()
  83
+
  84
+            result["success"] = True
  85
+            result["text"] = request.POST["text"]
  86
+
  87
+            return result
  88
+        else:
  89
+            return result
  90
+    else:
  91
+        return result
13 92
 
14 93
 
15 94
 @render_json
16 95
 def full(request):
17  
-    result = {}
  96
+    result = {"success": False}
18 97
     if request.POST:
19  
-        job = Job.objects.filter(published=True).get(pk=request.POST["id"])
20  
-        result['name'] = job.name
21  
-        result['desc'] = job.desc
22  
-        result['cat_image'] = job.category.image.__str__()
  98
+        job = Job.objects.filter(published=True).\
  99
+            get(pk=int(request.POST["id"]))
  100
+        image = job.category.image.order_by("?")[0].image
  101
+
  102
+        result["id"] = job.id
  103
+        result["link"] = job.link
  104
+        result["name"] = job.name
  105
+        result["desc"] = escape(job.desc)
  106
+        result["date"] = job.date.ctime()
  107
+        result["likes"] = job.likes
  108
+        result["cat_image"] = image.__str__()
  109
+
  110
+        comments = []
  111
+        c = Comments.objects.filter(job=job).all()
23 112
 
24  
-        return {"success": True, "vacancy": result}
  113
+        if c:
  114
+            for text in c:
  115
+                comments.append(escape(text.text))
  116
+
  117
+        return {"success": True,
  118
+                "vacancy": result,
  119
+                "comments": comments}
25 120
     else:
26  
-        return {"success": False}
  121
+        return result
  122
+
  123
+
  124
+@render_json
  125
+def like(request):
  126
+    result = {"success": False}
  127
+    if request.POST:
  128
+        id = int(request.POST["id"])
  129
+        type = request.POST["type"]
  130
+
  131
+        job = Job.objects.filter(pk=id).get()
  132
+
  133
+        if job:
  134
+            like = Likes.objects.filter(job=job,
  135
+                                        agent=request.META["HTTP_USER_AGENT"],
  136
+                                        ip=request.META["REMOTE_ADDR"])
  137
+            if like:
  138
+                result.update({"message": "Уже голосовали"})
  139
+                return result
  140
+            else:
  141
+                Likes.objects.create(job=job,
  142
+                                     type=type,
  143
+                                     agent=request.META["HTTP_USER_AGENT"],
  144
+                                     ip=request.META["REMOTE_ADDR"])
  145
+                if type == "like":
  146
+                    job.likes += 1
  147
+                    job.save()
  148
+                if type == "unlike":
  149
+                    job.likes -= 1
  150
+                    job.save()
  151
+                result.update({"success": True, "likes": job.likes})
  152
+        else:
  153
+            return result
  154
+    return result
20  public/static/css/style.css
@@ -213,7 +213,7 @@ input.button {
213 213
 	clear: both;
214 214
 	float: left;	
215 215
 	width: 790px;	
216  
-	padding: 0; 	
  216
+	padding: 0 0 10px 0;
217 217
 	background: #E8E8E8;	
218 218
 	border-top: 5px solid #FFF;
219 219
 	border-bottom: 2px solid #D0D0D0;
@@ -478,10 +478,26 @@ input.button {
478 478
     padding: 10px;
479 479
     width: 500px;
480 480
     left: 30%;
481  
-    position: absolute;
  481
+    position: fixed;
482 482
     z-index: 100;
483 483
     box-shadow: #8C9F0D 0px 0px 15px;
484 484
 }
  485
+#full .post-footer{
  486
+    height: 16px;
  487
+}
  488
+.popup .link{
  489
+    float: left;
  490
+}
  491
+.popup .likes{
  492
+    float: right;
  493
+}
  494
+.popup .like{
  495
+    cursor: pointer;
  496
+
  497
+}
  498
+.popup .like:hover{
  499
+    color: red;
  500
+}
485 501
 .popup .close{
486 502
     float: right;
487 503
     font-size: 30px;
BIN  public/static/images/1306311362719.png
19  public/static/js/jquery.validate.ru.js
... ...
@@ -0,0 +1,19 @@
  1
+jQuery.extend(jQuery.validator.messages, {
  2
+        required: "Это поле необходимо заполнить.",
  3
+        remote: "Пожалуйста, введите правильное значение.",
  4
+        email: "Пожалуйста, введите корректный адрес электронной почты.",
  5
+        url: "Пожалуйста, введите корректный URL.",
  6
+        date: "Пожалуйста, введите корректную дату.",
  7
+        dateISO: "Пожалуйста, введите корректную дату в формате ISO.",
  8
+        number: "Пожалуйста, введите число.",
  9
+        digits: "Пожалуйста, вводите только цифры.",
  10
+        creditcard: "Пожалуйста, введите правильный номер кредитной карты.",
  11
+        equalTo: "Пожалуйста, введите такое же значение ещё раз.",
  12
+        accept: "Пожалуйста, выберите файл с правильным расширением.",
  13
+        maxlength: jQuery.validator.format("Пожалуйста, введите не больше {0} символов."),
  14
+        minlength: jQuery.validator.format("Пожалуйста, введите не меньше {0} символов."),
  15
+        rangelength: jQuery.validator.format("Пожалуйста, введите значение длиной от {0} до {1} символов."),
  16
+        range: jQuery.validator.format("Пожалуйста, введите число от {0} до {1}."),
  17
+        max: jQuery.validator.format("Пожалуйста, введите число, меньшее или равное {0}."),
  18
+        min: jQuery.validator.format("Пожалуйста, введите число, большее или равное {0}.")
  19
+});
181  public/static/js/lol.js
@@ -6,12 +6,109 @@
6 6
  * To change this template use File | Settings | File Templates.
7 7
  */
8 8
 
9  
-$(document).ready(function() {
10  
-    $("#add").click(function(){
  9
+$(document).ready(function()
  10
+{
  11
+    var csrf = $("input[name=csrfmiddlewaretoken]").val();
  12
+
  13
+    $("#full .like").live('click', function()
  14
+    {
  15
+        var id = $("#full .counter");
  16
+        var type = $(this).attr('type');
  17
+
  18
+        $.post('/ajax/like/', {id: id.attr('id'), type: type, csrfmiddlewaretoken: csrf}, function(res)
  19
+        {
  20
+            if(res.success)
  21
+            {
  22
+                id.html(res.likes);
  23
+            }
  24
+            else
  25
+            {
  26
+                alert("Уже голосовали!")
  27
+            }
  28
+        }, "json");
  29
+    });
  30
+
  31
+
  32
+    $(".more").live('click', function()
  33
+    {
  34
+        var hidden = $("#main .hidden");
  35
+
  36
+        for(i=0; i<=hidden.length; i++)
  37
+        {
  38
+            $(hidden[i]).removeClass("hidden");
  39
+
  40
+            if(!hidden.length)
  41
+            {
  42
+                $(".morebut").remove();
  43
+            }
  44
+
  45
+            if(i == 9)
  46
+            {
  47
+                break;
  48
+            }
  49
+        }
  50
+    });
  51
+
  52
+    $("#nav ul li").click(function()
  53
+    {
  54
+        $.each($("#nav ul li"), function(index, elem)
  55
+        {
  56
+            elem.id = '';
  57
+        });
  58
+
  59
+        this.id = "current";
  60
+        var id = $(this).find('a').attr('id');
  61
+        var total = 0;
  62
+
  63
+        $.post("/ajax/fetch/", {cat: id, csrfmiddlewaretoken: csrf}, function(res)
  64
+        {
  65
+            $("#main").empty();
  66
+            total = 0;
  67
+
  68
+            $.each(res.jobs, function(index, job)
  69
+            {
  70
+                var JOB = '';
  71
+                var d = new Date(job.date);
  72
+                var m = parseInt(d.getMonth());
  73
+                if(total > 9)
  74
+                {
  75
+                    JOB += '<div class="cat_' + job.category + ' ' + total + ' hidden">';
  76
+                }
  77
+                else
  78
+                {
  79
+                    JOB += '<div class="cat_' + job.category + ' ' + total + '">';
  80
+                }
  81
+                JOB += '<h1>' + job.name + '</h1>';
  82
+                JOB += '<p>' + job.desc + '</p>';
  83
+                JOB += '<p class="post-footer">';
  84
+                JOB += '<a href="#full" class="readmore" id="' + job.id + '">Полностью</a> | ';
  85
+                JOB += 'Комментарии (' + job.comments + ') | ';
  86
+                JOB += '<span class="date">' + d.getDate() + ':' + (m+1) + ':' + d.getFullYear() + '</span> | ';
  87
+                JOB += '<span class="date">' + job.likes + '</span>';
  88
+                JOB += '</p>';
  89
+                JOB += '</div>';
  90
+
  91
+                $("#main").append(JOB);
  92
+
  93
+                total += 1;
  94
+            });
  95
+
  96
+            if(total > 10)
  97
+            {
  98
+                var HTML = '<p class="post-footer morebut" style="float: right;"><a href="#more" class="more">Больше</a></p>';
  99
+                $("#main").append(HTML);
  100
+            }
  101
+        }, "json");
  102
+    });
  103
+
  104
+    // show create vacancy form
  105
+    $("#add").click(function()
  106
+    {
11 107
         $(".add").show();
12 108
     });
13 109
 
14  
-    $(".close").click(function(){
  110
+    $(".close").click(function()
  111
+    {
15 112
         $(".popup, .bg").hide();
16 113
         $(".bg").css('background-image','');
17 114
     });
@@ -19,8 +116,10 @@ $(document).ready(function() {
19 116
     $("#addvacancy").validate({
20 117
         onkeyup: false,
21 118
         onblur : false,
22  
-        submitHandler: function() {
23  
-            $("#addvacancy").ajaxSubmit(function(res) {
  119
+        submitHandler: function()
  120
+        {
  121
+            $("#addvacancy").ajaxSubmit(function(res)
  122
+            {
24 123
                 if (res.success)
25 124
                 {
26 125
                     $(".error.true").show('slow');
@@ -34,21 +133,75 @@ $(document).ready(function() {
34 133
         }
35 134
     });
36 135
 
37  
-    $(".readmore").live('click', function(){
  136
+    $("#addcomment").validate({
  137
+        onkeyup: false,
  138
+        onblur : false,
  139
+        submitHandler: function()
  140
+        {
  141
+            $("#addcomment").ajaxSubmit(function(res)
  142
+            {
  143
+                var COMMENT = '';
  144
+
  145
+                if (res.success)
  146
+                {
  147
+                    COMMENT += '<li>';
  148
+                    COMMENT += '<p>' + res.text + '</p>';
  149
+                    COMMENT += '</li>';
  150
+
  151
+                    $("textarea[name=text]").val('');
  152
+                    $("#full .comments h1").remove();
  153
+                    $("#full .comments").append(COMMENT);
  154
+                }
  155
+                else
  156
+                {
  157
+                    $(".error.false").show('slow');
  158
+                }
  159
+            });
  160
+        }
  161
+    });
  162
+
  163
+    $(".readmore").live('click', function()
  164
+    {
38 165
         var id = this.id;
39  
-        var csrf = $("input[name=csrfmiddlewaretoken]").val();
40  
-        $.post('/ajax/full/',{id:id, csrfmiddlewaretoken: csrf}, function(res){
  166
+
  167
+        $.post('/ajax/full/',{id:id, csrfmiddlewaretoken: csrf}, function(res)
  168
+        {
41 169
             var v = res.vacancy;
42  
-            var HTML = '';
43  
-            console.log(v);
  170
+            var DESC = '';
  171
+            var COMM = '';
  172
+
44 173
             if(res.success)
45 174
             {
46  
-                HTML += '<h3>'+v.name+'</h3>';
47  
-                HTML += '<p>'+v.desc+'</p>';
  175
+                $("input[name=job]").val(v.id);
  176
+
  177
+                DESC += '<h3>'+v.name+'</h3>';
  178
+                DESC += '<p>'+v.desc+'</p>';
  179
+                DESC += '<p class="post-footer">';
  180
+                DESC += '<span class="date link"><a href="' + v.link + '" title="' + v.link + '" target="_blank">Оригинал</a></span>';
  181
+                DESC += '<span class="date likes"><span type="like" class="like">ГАГАГА</span>  ';
  182
+                DESC += '<span class="counter" id="' + v.id + '">'+v.likes+'</span>';
  183
+                DESC += '  <span type="unlike" class="like">WTF?</span> </span>';
  184
+                DESC += '</p>';
  185
+
  186
+                if(res.comments.length > 0)
  187
+                {
  188
+                    $.each(res.comments, function(index, comment)
  189
+                    {
  190
+                        COMM += '<li>';
  191
+                        COMM += '<p>' + comment + '</p>';
  192
+                        COMM += '</li>';
  193
+                    });
  194
+                }
  195
+                else
  196
+                {
  197
+                    COMM = '<h1>Нет комментариев</h1>';
  198
+                }
  199
+
48 200
                 $(".bg").css('background', 'url(/media/' + v.cat_image + ')');
49  
-                console.log('/media/'+v.cat_image);
50 201
                 $("#full, .bg").show();
51  
-                $("#full .desc").html(HTML);
  202
+
  203
+                $("#full .desc").html(DESC);
  204
+                $("#full .comments").html(COMM);
52 205
             }
53 206
             {
54 207
                 $("#full").show();
0  public/templates/includes/create.html
No changes.
357  public/templates/jobs.html
... ...
@@ -1,280 +1,105 @@
1  
-{% load forms %}
2  
-{% csrf_token %}
3  
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4  
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5  
-<head>
6  
-    <meta name="Description" content="Information architecture, Web Design, Web Standards." />
7  
-    <meta name="Keywords" content="your, keywords" />
8  
-    <meta http-equiv="Content-Type" content="text/html; charset=urf-8" />
9  
-    <meta name="Distribution" content="Global" />
10  
-    <meta name="Robots" content="index,follow" />
  1
+<!DOCTYPE html>
  2
+<html>
  3
+  <head>
  4
+    <meta charset="utf-8">
  5
+    {% csrf_token %}
11 6
     <link rel="stylesheet" href="{{ STATIC_URL }}css/style.css" type="text/css" />
12 7
     <script type="text/javascript" src="{{ STATIC_URL }}js/jquery-1.7.1.min.js"></script>
13 8
     <script type="text/javascript" src="{{ STATIC_URL }}js/jquery.form.js"></script>
14 9
     <script type="text/javascript" src="{{ STATIC_URL }}js/jquery.validate.min.js"></script>
  10
+    <script type="text/javascript" src="{{ STATIC_URL }}js/jquery.validate.ru.js"></script>
15 11
     <script type="text/javascript" src="{{ STATIC_URL }}js/lol.js"></script>
16  
-    <title>ЖОПЛУЛЗ ГАГАГА</title></head>
17  
-<body>
18  
-<div class="bg hidden"></div>
19  
-<div id="full" class="popup hidden">
20  
-    <div class="close">x</div>
21  
-    <div class="desc">
22  
-
  12
+    <title>ЛУЛЗДЖОБ</title>
  13
+  </head>
  14
+  <body>
  15
+    <div class="bg hidden"></div>
  16
+    <div id="full" class="popup hidden">
  17
+      <div class="close">x</div>
  18
+      <div class="desc"></div>
  19
+      <div class="commentaries" style="text-align: left;">
  20
+        <h3>Комментарии</h3>
  21
+        <ul class="comments"></ul>
  22
+        <div class="addcomment">
  23
+          <form action="/ajax/addcomment/" method="post" id="addcomment">
  24
+            <fieldset>
  25
+              {% csrf_token %}
  26
+              <p>
  27
+                {{ addcomment }}
  28
+                <br/>
  29
+                <input name="submit" class="button sendcomment" type="submit"/>
  30
+              </p>
  31
+            </fieldset>
  32
+          </form>
  33
+        </div>
  34
+      </div>
23 35
     </div>
24  
-    <div class="comments">
25  
-
26  
-    </div>
27  
-</div>
28  
-<div class="popup add hidden">
29  
-    <div class="close">x</div>
30  
-    <h3>Добавить вакансию</h3>
31  
-    <div class="error true hidden">Вакансия добавлена на рассмотрение</div>
32  
-    <div class="error false hidden">ЧТО ТО ПОШЛО НЕ ТАК! ЭВОКУИРУЕМСЯ!</div>
33  
-    <form action="/ajax/addvacancy/" method="post" id="addvacancy">
  36
+    <div class="popup add hidden" style="text-align: left;">
  37
+      <div class="close">x</div>
  38
+      <h3>Добавить вакансию</h3>
  39
+      <div class="error true hidden">Вакансия добавлена на рассмотрение</div>
  40
+      <div class="error false hidden">ЧТО ТО ПОШЛО НЕ ТАК! ЭВОКУИРУЕМСЯ!</div>
  41
+      <form action="/ajax/addvacancy/" method="post" id="addvacancy">
34 42
         <fieldset>
35  
-        {% csrf_token %}
36  
-        <p>
37  
-            {% addjob %}
  43
+          {% csrf_token %}
  44
+          <p>
  45
+            {{ addjob }}
38 46
             <br/><br/>
39 47
             <input name="submit" class="button addvacancy" type="submit"/>
40  
-        </p>
  48
+          </p>
41 49
         </fieldset>
42  
-    </form>
43  
-</div>
44  
-<!-- wrap starts here -->
45  
-<div id="wrap">
46  
-	<div id="top-bg"></div>
47  
-	<!--header -->
48  
-	<div id="header">
49  
-		<h1 id="logo-text"><a href="#" title="">ДЖОП<span>ЛУЛЗ</span></a></h1>
50  
-		<h2 id="slogan">самые ёбнутые вакансии</h2>
  50
+      </form>
  51
+    </div>
  52
+    <div id="wrap">
  53
+      <div id="top-bg"></div>
  54
+      <div id="header">
  55
+        <h1 id="logo-text"><a href="{{ BASE_URL }}" title="ЛУЛЗДЖОБ">ЛУЛЗ<span>ДЖОБ</span></a></h1>
  56
+        <h2 id="slogan" title="Наркоманы штоле?">Самые ёбнутые вакансии рунета</h2>
51 57
         <button id="add">Добавить</button>
52  
-	<!--header ends-->
53  
-	</div>
54  
-	<!-- navigation starts-->
55  
-
56  
-	<div  id="nav">
57  
-		<ul>
58  
-			<li>{% search %}</li>
59  
-		</ul>
60  
-	<!-- navigation ends-->
61  
-	</div>
62  
-    {% comment %}
63  
-	{% endcomment %}
64  
-
65  
-	<!-- content-wrap starts -->
66  
-	<div id="content-wrap">
67  
-		<div id="sidebar">
68  
-			<h1>Поиск</h1>
69  
-			<form action="#" class="searchform">
70  
-				<p>
71  
-  				<input name="search" class="button" value="Search" type="submit" />
72  
-				</p>
73  
-			</form>
74  
-
75  
-			<h1>Sidebar Menu</h1>
76  
-			<ul class="sidemenu">
77  
-				<li><a href="#">Home</a></li>
78  
-				<li><a href="#TemplateInfo">Template Info</a></li>
79  
-				<li><a href="#SampleTags">Sample Tags</a></li>
80  
-				<li><a href="http://www.styleshout.com/">More Free Templates</a></li>
81  
-				<li><a href="http://www.4templates.com/?aff=ealigam">Premium Templates</a></li>
82  
-			</ul>
83  
-
84  
-			<h1>Links</h1>
85  
-			<ul class="sidemenu">
86  
-				<li><a href="http://www.pdphoto.org/">PDPhoto.org</a></li>
87  
-				<li><a href="http://www.squidfingers.com/patterns/">Squidfingers | Patterns</a></li>
88  
-				<li><a href="http://www.alistapart.com">Alistapart</a></li>
89  
-				<li><a href="http://www.cssremix.com">CSS Remix</a></li>
90  
-				<li><a href="http://www.dark-i.com/">Dark Eye</a></li>
91  
-			</ul>
92  
-
93  
-			<h1>Sponsors</h1>
94  
-			<ul class="sidemenu">
95  
-				<li><a href="http://www.4templates.com/?aff=ealigam"><strong>4templates</strong></a> <br /> Low Cost Hi-Quality Templates</li>
96  
-				<li><a href="http://store.templatemonster.com?aff=ealigam"><strong>TemplateMonster</strong></a> <br /> Delivering the Best Templates on the Net!</li>
97  
-				<li><a href="http://www.fotolia.com/partner/114283"><strong>Fotolia</strong></a> <br /> Free stock images or from $1</li>
98  
-				<li><a href="http://www.text-link-ads.com/?ref=40025"><strong>Text Link Ads</strong></a> <br /> Monetized your website</li>
99  
-				<li><a href="http://www.dreamhost.com/r.cgi?287326"><strong>Dreamhost</strong></a> <br /> Premium webhosting</li>
100  
-			</ul>
101  
-
102  
-			<h1>Wise Words</h1>
103  
-			<p>&quot;Great works are performed not by strength,
104  
-			but by perseverance.&quot; </p>
105  
-
106  
-			<p class="align-right">- Samuel Johnson</p>
107  
-
108  
-			<h1>Support Styleshout</h1>
109  
-			<p>If you are interested in supporting my work and would like to contribute, you are
110  
-			welcome to make a small donation through the
111  
-			<a href="http://www.styleshout.com/">donate link</a> on my website - it will
112  
-			be a great help and will surely be appreciated.</p>
113  
-
114  
-		<!-- sidebar ends -->
115  
-		</div>
116  
-
117  
-		<div id="main">
118  
-            {% if jobs %}
119  
-                {% for job in jobs %}
120  
-                <div class="cat_{{ job.category.id }}">
121  
-                    <a name="TemplateInfo"></a>
122  
-                    <h1>{{ job.name }}</h1>
123  
-                    <p>{{ job.desc }}</p>
124  
-                    <p class="post-footer">
125  
-                        <a href="#full" class="readmore" id="{{ job.id }}">Смотреть полностью</a> |
126  
-                        <a href="#" class="comments">Комментарии ({{ likes.comments.all|length }})</a> |
127  
-                        <span class="date">{{ job.date|date:"d:m:Y" }}</span> |
128  
-                        <span class="date">{{ job.likes.all|length }}</span>
129  
-
130  
-                    </p>
131  
-                </div>
132  
-                {% endfor %}
  58
+      </div>
  59
+      <div id="nav">
  60
+        <ul>
  61
+          <li id="current"><a id="900009" href="#all" title="Все">Все</a></li>{% for category in categories %}
  62
+          <li><a id="{{ category.id }}" href="#{{ category.name }}" title="{{ category.name }}">{{ category.name }}</a></li>{% endfor %}
  63
+        </ul>
  64
+      </div>
  65
+      <div id="content-wrap">
  66
+        <div id="sidebar">
  67
+          <img src="{{ STATIC_URL }}images/1306311362719.png" alt="WTF">
  68
+        </div>
  69
+        <div id="main">
  70
+        {% if jobs %}
  71
+          {% for job in jobs %}
  72
+            <article>
  73
+            {% if forloop.counter0 > 9 %}
  74
+            <div class="cat_{{ job.category.id }} hidden {{ forloop.counter0 }}">
133 75
             {% else %}
134  
-                <h1>Нет вакансий</h1>
  76
+            <div class="cat_{{ job.category.id }} {{ forloop.counter0 }}">
135 77
             {% endif %}
136  
-            {% comment %}
137  
-
138  
-			<h1>Sample Tags</h1>
139  
-
140  
-			<h3>Code</h3>
141  
-			<p><code>
142  
-			code-sample { <br />
143  
-			font-weight: bold;<br />
144  
-			font-style: italic;<br />
145  
-			}
146  
-			</code></p>
147  
-
148  
-			<h3>Example Lists</h3>
149  
-
150  
-			<ol>
151  
-				<li>Here is an example</li>
152  
-				<li>of an ordered list</li>
153  
-			</ol>
154  
-
155  
-			<ul>
156  
-				<li>Here is an example</li>
157  
-				<li>of an unordered list</li>
158  
-			</ul>
159  
-
160  
-			<h3>Blockquote</h3>
161  
-			<blockquote><p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy
162  
-			nibh euismod tincidunt ut laoreet dolore magna aliquam erat....</p></blockquote>
163  
-
164  
-			<h3>Image and text</h3>
165  
-			<p><a href="http://getfirefox.com/"><img src="images/firefox-gray.jpg" width="100" height="120" alt="firefox" class="float-left" /></a>
166  
-			Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec libero. Suspendisse bibendum.
167  
-			Cras id urna. Morbi tincidunt, orci ac convallis aliquam, lectus turpis varius lorem, eu
168  
-			posuere nunc justo tempus leo. Donec mattis, purus nec placerat bibendum, dui pede condimentum
169  
-			odio, ac blandit ante orci ut diam. Cras fringilla magna. Phasellus suscipit, leo a pharetra
170  
-			condimentum, lorem tellus eleifend magna, eget fringilla velit magna id neque. Curabitur vel urna.
171  
-			In tristique orci porttitor ipsum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec libero. Suspendisse bibendum.
172  
-			Cras id urna. Morbi tincidunt, orci ac convallis aliquam, lectus turpis varius lorem, eu
173  
-			posuere nunc justo tempus leo.
174  
-			</p>
175  
-
176  
-			<h3>Table Styling</h3>
177  
-			<table>
178  
-				<tr>
179  
-					<th class="first"><strong>post</strong> date</th>
180  
-					<th>title</th>
181  
-					<th>description</th>
182  
-				</tr>
183  
-				<tr class="row-a">
184  
-					<td class="first">04.18.2007</td>
185  
-					<td><a href="#">Augue non nibh</a></td>
186  
-					<td><a href="#">Lobortis commodo metus vestibulum</a></td>
187  
-				</tr>
188  
-				<tr class="row-b">
189  
-					<td class="first">04.18.2007</td>
190  
-					<td><a href="#">Fusce ut diam bibendum</a></td>
191  
-					<td><a href="#">Purus in eget odio in sapien</a></td>
192  
-				</tr>
193  
-				<tr class="row-a">
194  
-					<td class="first">04.18.2007</td>
195  
-					<td><a href="#">Maecenas et ipsum</a></td>
196  
-					<td><a href="#">Adipiscing blandit quisque eros</a></td>
197  
-				</tr>
198  
-				<tr class="row-b">
199  
-					<td class="first">04.18.2007</td>
200  
-					<td><a href="#">Sed vestibulum blandit</a></td>
201  
-					<td><a href="#">Cras lobortis commodo metus lorem</a></td>
202  
-				</tr>
203  
-			</table>
204  
-            {% endcomment %}
205  
-		<!-- main ends -->
206  
-		</div>
207  
-
208  
-	<!-- content-wrap ends-->
209  
-	</div>
210  
-
211  
-	<!-- footer starts -->
212  
-	<div id="footer-wrap">
213  
-        {% comment %}
214  
-		<div id="footer-columns">
215  
-
216  
-			<div class="col3">
217  
-				<h2>Tincidunt</h2>
218  
-				<ul>
219  
-					<li><a href="#">consequat molestie</a></li>
220  
-					<li><a href="#">sem justo</a></li>
221  
-					<li><a href="#">semper</a></li>
222  
-					<li><a href="#">magna sed purus</a></li>
223  
-					<li><a href="#">tincidunt</a></li>
224  
-				</ul>
225  
-			</div>
226  
-
227  
-			<div class="col3-center">
228  
-				<h2>Sed purus</h2>
229  
-				<ul>
230  
-					<li><a href="#">consequat molestie</a></li>
231  
-					<li><a href="#">sem justo</a></li>
232  
-					<li><a href="#">semper</a></li>
233  
-					<li><a href="#">magna sed purus</a></li>
234  
-					<li><a href="#">tincidunt</a></li>
235  
-				</ul>
236  
-			</div>
237  
-
238  
-			<div class="col3">
239  
-				<h2>Praesent</h2>
240  
-				<ul>
241  
-					<li><a href="#">consequat molestie</a></li>
242  
-					<li><a href="#">sem justo</a></li>
243  
-					<li><a href="#">semper</a></li>
244  
-					<li><a href="#">magna sed purus</a></li>
245  
-					<li><a href="#">tincidunt</a></li>
246  
-				</ul>
247  
-			</div>
248  
-		<!-- footer-columns ends -->
249  
-    </div>
250  
-    {% endcomment %}
251  
-		<div id="footer-bottom">
252  
-
253  
-			<p>
254  
-			&copy; 2011 <strong>ДЖОПЛУЛЗ</strong>
255  
-        {% comment %} |
256  
-			Design by: <a href="http://www.styleshout.com/">styleshout</a> |
257  
-			Valid <a href="http://validator.w3.org/check?uri=referer">XHTML</a> |
258  
-			<a href="http://jigsaw.w3.org/css-validator/check/referer">CSS</a>
259  
-   		&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
260  
-        <a href="#">Home</a>&nbsp;|&nbsp;
261  
-   		<a href="#">Sitemap</a>&nbsp;|&nbsp;
262  
-	   	<a href="#">RSS Feed</a>
263  
-   		</p>
264  
-   		{% endcomment %}
265  
-
266  
-
  78
+              <h1>{{ job.name }}</h1>
  79
+              <p>{{ job.desc }}</p>
  80
+              <p class="post-footer">
  81
+                <a href="#full" class="readmore" id="{{ job.id }}">Полностью</a> |
  82
+                Комментарии ({{ job.jobcomm.count }}) |
  83
+                <span class="date">{{ job.date|date:"j:m:Y" }}</span> |
  84
+                <span class="date likes">Рейтинг: {{ job.likes }}</span>
  85
+              </p>
  86
+            </div>
  87
+            </article>
  88
+          {% endfor %}
  89
+          {% if count > 10 %}
  90
+            <p class="post-footer morebut" style="float: right;"><a href="#more" class="more">Больше</a></p>
  91
+          {% endif %}
  92
+        {% else %}
  93
+          <h1>ПРИШЛО ВРЕМЯ ДОБАВИТЬ ВАКАНСИЙ</h1>
  94
+        {% endif %}
  95
+        </div>
  96
+      </div>
  97
+      <div id="footer-wrap">
  98
+        <div id="footer-bottom">
  99
+          <p>&copy; 2011 <strong>ЛУЛЗДЖОБ</strong></p>
  100
+        </div>
  101
+      </div>
267 102
     </div>
268  
-    <!-- footer ends-->
269  
-</div>
270  
-<!-- wrap ends here -->
271  
-</div>
272  
-
273  
-</body>
274  
-</html>
275  
-
276  
-
277  
-
278  
-<hr>
279  
-{% addcomment %}
280  
-<hr>
  103
+  </div>
  104
+  </body>
  105
+</html>
11  urls.py
... ...
@@ -1,7 +1,5 @@
1 1
 from django.conf.urls.defaults import patterns, include, url
2  
-from django.views.generic.list import ListView
3  
-from lulz.models import Job
4  
-from lulz.views import addvacancy, full
  2
+from lulz.views import home, addvacancy, full, addcomment, fetch, like
5 3
 import settings
6 4
 
7 5
 # Uncomment the next two lines to enable the admin:
@@ -9,12 +7,13 @@
9 7
 admin.autodiscover()
10 8
 
11 9
 urlpatterns = patterns('',
12  
-    url(r'^$', ListView.as_view(queryset=Job.objects.filter(published=True).all()[:10],
13  
-                                     context_object_name="jobs",
14  
-                                     template_name="jobs.html")),
  10
+    url(r'^$', home),
15 11
     url(r'^admin/', include(admin.site.urls)),
16 12
     url(r'^ajax/addvacancy/$', addvacancy),
  13
+    url(r'^ajax/addcomment/$', addcomment),
17 14
     url(r'^ajax/full/$', full),
  15
+    url(r'^ajax/fetch/$', fetch),
  16
+    url(r'^ajax/like/$', like),