Permalink
Browse files

first commit

  • Loading branch information...
0 parents commit 7462abd2c3dea5730fabb8453b9d2f12828829b4 @robmoggach committed Oct 2, 2012
@@ -0,0 +1,9 @@
+* eol=lf
+*.png binary
+*.jpg binary
+*.gif binary
+*.jar binary
+*.exe binary
+*.eot binary
+*.ttf binary
+*.pdf binary
@@ -0,0 +1,25 @@
+*~
+*.db
+*.orig
+*.pyc
+*.pyo
+*.rej
+.installed.cfg
+eggs
+log
+parts
+tmp
+.DS_Store
+.hg
+src/*.egg-info
+dist
+pip-log.txt
+.Python
+lib
+.mr.developer.cfg
+src
+passwords.py
+settings_local.py
+build
+apache2
+*.py.swp
@@ -0,0 +1,2 @@
+glob:*.py[cow]
+glob:.emacs*
@@ -0,0 +1,23 @@
+Copyright (c) 2012, Robert Moggach
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,4 @@
+exclude .hgignore
+include CHANGELOG LICENSE README.rst
+recursive-include mezzanine-careers *
+
@@ -0,0 +1,34 @@
+==================
+ Mezzanine Careers
+==================
+
+Mezzanine Careers is a simple Job Posting application built for the `Django`_ based CMS `Mezzanine`_.
+
+Features
+========
+
+* Create a list of job posting with delayed and expiring durations
+* Provide basic templates to get started
+* Seamlessly integrate with the Mezzanine CMS
+
+Installation and Usage
+======================
+
+Install the app by using `pip`_::
+
+ $ pip install mezzanine-careers
+
+Add ``careers`` to ``INSTALLED_APPS`` and synchronize/migrate the database.
+
+Go to the admin site and create new polls in the ``Pages`` section
+
+Development
+===========
+
+New features and fixes are welcome. Better if it comes with a patch or pull request. You can find the latest development sources at `GitHub`_.
+Issues are tracked at the GitHub project page.
+
+.. _`Mezzanine`: http://mezzanine.jupo.org/
+.. _`Django`: http://djangoproject.com/
+.. _`pip`: http://www.pip-installer.org/
+.. _`GitHub`: https://github.com/mogga/mezzanine-careers
@@ -0,0 +1 @@
+__version__ = 0.1
@@ -0,0 +1,28 @@
+
+from copy import deepcopy
+
+from django.contrib import admin
+
+from careers.models import JobPost
+from mezzanine.conf import settings
+from mezzanine.core.admin import DisplayableAdmin
+
+
+jobpost_fieldsets = deepcopy(DisplayableAdmin.fieldsets)
+jobpost_fieldsets[0][1]["fields"].extend(["content",])
+jobpost_list_display = ["title", "status", "admin_link"]
+
+
+class JobPostAdmin(DisplayableAdmin):
+ """
+ Admin class for job posts.
+ """
+
+ fieldsets = jobpost_fieldsets
+ list_display = jobpost_list_display
+
+ def save_form(self, request, form, change):
+ return DisplayableAdmin.save_form(self, request, form, change)
+
+
+admin.site.register(JobPost, JobPostAdmin)
@@ -0,0 +1,19 @@
+from django.utils.translation import ugettext_lazy as _
+
+from mezzanine.conf import register_setting
+
+
+register_setting(
+ name="jobpostS_PER_PAGE",
+ label=_("Job Posts per page"),
+ description=_("Number of job posts shown on a career listing page."),
+ editable=True,
+ default=7,
+)
+
+register_setting(
+ name="jobpost_SLUG",
+ description=_("Slug of the page object for the careers app."),
+ editable=False,
+ default="jobpost",
+)
@@ -0,0 +1,25 @@
+from django import forms
+
+from careers.models import JobPost
+
+
+hidden_field_defaults = ("status", "gen_description")
+
+
+class JobPostForm(forms.ModelForm):
+ """
+ Model form for ``JobPost`` that provides the quick job post panel in the
+ admin dashboard.
+ """
+
+ class Meta:
+ model = JobPost
+ fields = ("title", "content") + hidden_field_defaults
+
+ def __init__(self):
+ initial = {}
+ for field in hidden_field_defaults:
+ initial[field] = JobPost._meta.get_field(field).default
+ super(JobPostForm, self).__init__(initial=initial)
+ for field in hidden_field_defaults:
+ self.fields[field].widget = forms.HiddenInput()
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding model 'JobPost'
+ db.create_table('careers_jobpost', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('keywords_string', self.gf('django.db.models.fields.CharField')(max_length=500, blank=True)),
+ ('site', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['sites.Site'])),
+ ('title', self.gf('django.db.models.fields.CharField')(max_length=500)),
+ ('slug', self.gf('django.db.models.fields.CharField')(max_length=2000, null=True, blank=True)),
+ ('_meta_title', self.gf('django.db.models.fields.CharField')(max_length=500, null=True, blank=True)),
+ ('description', self.gf('django.db.models.fields.TextField')(blank=True)),
+ ('gen_description', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ('status', self.gf('django.db.models.fields.IntegerField')(default=2)),
+ ('publish_date', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
+ ('expiry_date', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
+ ('short_url', self.gf('django.db.models.fields.URLField')(max_length=200, null=True, blank=True)),
+ ('content', self.gf('mezzanine.core.fields.RichTextField')()),
+ ('keywords', self.gf('mezzanine.generic.fields.KeywordsField')(object_id_field='object_pk', to=orm['generic.AssignedKeyword'], frozen_by_south=True)),
+ ))
+ db.send_create_signal('careers', ['JobPost'])
+
+
+ def backwards(self, orm):
+ # Deleting model 'JobPost'
+ db.delete_table('careers_jobpost')
+
+
+ models = {
+ 'careers.jobpost': {
+ 'Meta': {'ordering': "('-publish_date',)", 'object_name': 'JobPost'},
+ '_meta_title': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True', 'blank': 'True'}),
+ 'content': ('mezzanine.core.fields.RichTextField', [], {}),
+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'expiry_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'gen_description': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'keywords': ('mezzanine.generic.fields.KeywordsField', [], {'object_id_field': "'object_pk'", 'to': "orm['generic.AssignedKeyword']", 'frozen_by_south': 'True'}),
+ 'keywords_string': ('django.db.models.fields.CharField', [], {'max_length': '500', 'blank': 'True'}),
+ 'publish_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'short_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}),
+ 'slug': ('django.db.models.fields.CharField', [], {'max_length': '2000', 'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.IntegerField', [], {'default': '2'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'generic.assignedkeyword': {
+ 'Meta': {'ordering': "('_order',)", 'object_name': 'AssignedKeyword'},
+ '_order': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'keyword': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'assignments'", 'to': "orm['generic.Keyword']"}),
+ 'object_pk': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'generic.keyword': {
+ 'Meta': {'object_name': 'Keyword'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}),
+ 'slug': ('django.db.models.fields.CharField', [], {'max_length': '2000', 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+ },
+ 'sites.site': {
+ 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
+ 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ }
+ }
+
+ complete_apps = ['careers']
No changes.
@@ -0,0 +1,26 @@
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+
+from mezzanine.conf import settings
+from mezzanine.core.models import Displayable, RichText, Ownable
+
+
+class JobPost(Displayable, RichText):
+ """
+ A career job posting
+ """
+
+ class Meta:
+ verbose_name = _("Job Post")
+ verbose_name_plural = _("Job Posts")
+ ordering = ("-publish_date",)
+
+ @models.permalink
+ def get_absolute_url(self):
+ url_name = "jobpost_detail"
+ kwargs = {"slug": self.slug}
+ return (url_name, (), kwargs)
+
+ def keyword_list(self):
+ return getattr(self, "_keywords", self.keywords.all())
+
@@ -0,0 +1,33 @@
+{% load i18n %}
+
+{% if perms.careers.add_jobpost and perms.careers.change_jobpost %}
+<script>
+// Format newlines for HTML in the quick blog form, since the content
+// is HTML but the form field is plain text.
+$(function() {
+ $('#quick-job-post-form').submit(function() {
+ var field = $('#quick-job-post-form #id_content');
+ var value = field.attr('value').split('\n\n').join('</p><p>');
+ value = '<p>' + value.split('\n').join('<br>') + '</p>';
+ field.attr('value', value);
+ return true;
+ });
+});
+</script>
+<div class="module">
+ <h2>{% trans "Quick Job Post" %}</h2>
+ <form method="post" id="quick-job-post-form" action="{% url admin:careers_jobpost_add %}">
+ {% csrf_token %}
+ <table id="quick-job-post">
+ {{ form.as_table }}
+ <tr>
+ <td>&nbsp;</td>
+ <td style="width:100%;text-align:right;">
+ <input type="submit" class="default"
+ value="{% trans "Save Draft" %}" />
+ </td>
+ </tr>
+ </table>
+ </form>
+</div>
+{% endif %}
@@ -0,0 +1,42 @@
+{% load career_tags keyword_tags i18n %}
+
+{% jobpost_recent_posts 5 as recent_posts %}
+{% if recent_posts %}
+<h3>{% trans "Recent Posts" %}</h3>
+<ul class="unstyled recent-posts">
+{% for recent_post in recent_posts %}
+<li><a href="{{ recent_post.get_absolute_url }}"
+ >{{ recent_post.title }}</a></li>
+{% endfor %}
+</ul>
+{% endif %}
+
+{% jobpost_months as months %}
+{% if months %}
+<h3>{% trans "Archive" %}</h3>
+{% for month in months %}
+ {% ifchanged month.date.year %}
+ {% if not forloop.first %}</ul>{% endif %}
+ <h6>{{ month.date.year }}</h6><ul class="unstyled">
+ {% endifchanged %}
+ <li><a href="{% url jobpost_list_month year=month.date.year month=month.date.month %}"
+ >{{ month.date|date:"F" }}</a> ({{ month.post_count }})</li>
+{% endfor %}
+</ul>
+{% endif %}
+
+{% keywords_for careers.jobpost as tags %}
+{% if tags %}
+<h3>{% trans "Tags" %}</h3>
+<ul class="unstyled tags">
+{% for tag in tags %}
+<li>
+ <a href="{% url jobpost_list_tag tag.slug %}"
+ class="tag-weight-{{ tag.weight }}">{{ tag }}</a>
+ ({{ tag.item_count }})
+</li>
+{% endfor %}
+</ul>
+{% endif %}
+
+
Oops, something went wrong.

0 comments on commit 7462abd

Please sign in to comment.