zinnia.xmlrpc.metaweblog
Covered: 246 lines
Missed: 0 lines
Skipped 51 lines
Percent: 100 %
  1
"""XML-RPC methods of Zinnia metaWeblog API"""
  2
import os
  3
from datetime import datetime
  4
from xmlrpclib import Fault
  5
from xmlrpclib import DateTime
  7
from django.conf import settings
  8
from django.contrib.auth.models import User
  9
from django.contrib.sites.models import Site
 10
from django.core.urlresolvers import reverse
 11
from django.utils.translation import gettext as _
 12
from django.utils.html import strip_tags
 13
from django.utils.text import truncate_words
 14
from django.core.files.base import ContentFile
 15
from django.core.files.storage import default_storage
 16
from django.template.defaultfilters import slugify
 18
from zinnia.models import Entry
 19
from zinnia.models import Category
 20
from zinnia.settings import PROTOCOL
 21
from zinnia.settings import UPLOAD_TO
 22
from zinnia.managers import DRAFT, PUBLISHED
 23
from django_xmlrpc.decorators import xmlrpc_func
 26
LOGIN_ERROR = 801
 27
PERMISSION_DENIED = 803
 30
def authenticate(username, password, permission=None):
 31
    """Authenticate staff_user with permission"""
 32
    try:
 33
        user = User.objects.get(username__exact=username)
 34
    except User.DoesNotExist:
 35
        raise Fault(LOGIN_ERROR, _('Username is incorrect.'))
 36
    if not user.check_password(password):
 37
        raise Fault(LOGIN_ERROR, _('Password is invalid.'))
 38
    if not user.is_staff or not user.is_active:
 39
        raise Fault(PERMISSION_DENIED, _('User account unavailable.'))
 40
    if permission:
 41
        if not user.has_perm(permission):
 42
            raise Fault(PERMISSION_DENIED, _('User cannot %s.') % permission)
 43
    return user
 46
def blog_structure(site):
 47
    """A blog structure"""
 48
    return {'url': '%s://%s%s' % (
 49
        PROTOCOL, site.domain, reverse('zinnia_entry_archive_index')),
 50
            'blogid': settings.SITE_ID,
 51
            'blogName': site.name}
 54
def user_structure(user, site):
 55
    """An user structure"""
 56
    return {'userid': user.pk,
 57
            'email': user.email,
 58
            'nickname': user.username,
 59
            'lastname': user.last_name,
 60
            'firstname': user.first_name,
 61
            'url': '%s://%s%s' % (
 62
                PROTOCOL, site.domain,
 63
                reverse('zinnia_author_detail', args=[user.username]))}
 66
def author_structure(user):
 67
    """An author structure"""
 68
    return {'user_id': user.pk,
 69
            'user_login': user.username,
 70
            'display_name': user.username,
 71
            'user_email': user.email}
 74
def category_structure(category, site):
 75
    """A category structure"""
 76
    return {'description': category.title,
 77
            'htmlUrl': '%s://%s%s' % (
 78
                PROTOCOL, site.domain,
 79
                category.get_absolute_url()),
 80
            'rssUrl': '%s://%s%s' % (
 81
                PROTOCOL, site.domain,
 82
                reverse('zinnia_category_feed', args=[category.tree_path])),
 84
            'categoryId': category.pk,
 85
            'parentId': category.parent and category.parent.pk or 0,
 86
            'categoryDescription': category.description,
 87
            'categoryName': category.title}
 90
def post_structure(entry, site):
 91
    """A post structure with extensions"""
 92
    author = entry.authors.all()[0]
 93
    return {'title': entry.title,
 94
            'description': unicode(entry.html_content),
 95
            'link': '%s://%s%s' % (PROTOCOL, site.domain,
 96
                                   entry.get_absolute_url()),
 98
            'permaLink': '%s://%s%s' % (PROTOCOL, site.domain,
 99
                                        entry.get_absolute_url()),
100
            'categories': [cat.title for cat in entry.categories.all()],
101
            'dateCreated': DateTime(entry.creation_date.isoformat()),
102
            'postid': entry.pk,
103
            'userid': author.username,
105
            'mt_excerpt': entry.excerpt,
106
            'mt_allow_comments': int(entry.comment_enabled),
107
            'mt_allow_pings': int(entry.pingback_enabled),
108
            'mt_keywords': entry.tags,
110
            'wp_author': author.username,
111
            'wp_author_id': author.pk,
112
            'wp_author_display_name': author.username,
113
            'wp_password': entry.password,
114
            'wp_slug': entry.slug,
115
            'sticky': entry.featured}
118
@xmlrpc_func(returns='struct[]', args=['string', 'string', 'string'])
119
def get_users_blogs(apikey, username, password):
120
    """blogger.getUsersBlogs(api_key, username, password)
121
    => blog structure[]"""
122
    authenticate(username, password)
123
    site = Site.objects.get_current()
124
    return [blog_structure(site)]
127
@xmlrpc_func(returns='struct', args=['string', 'string', 'string'])
128
def get_user_info(apikey, username, password):
129
    """blogger.getUserInfo(api_key, username, password)
130
    => user structure"""
131
    user = authenticate(username, password)
132
    site = Site.objects.get_current()
133
    return user_structure(user, site)
136
@xmlrpc_func(returns='struct[]', args=['string', 'string', 'string'])
137
def get_authors(apikey, username, password):
138
    """wp.getAuthors(api_key, username, password)
139
    => author structure[]"""
140
    authenticate(username, password)
141
    return [author_structure(author)
142
            for author in User.objects.filter(is_staff=True)]
145
@xmlrpc_func(returns='boolean', args=['string', 'string',
146
                                      'string', 'string', 'string'])
147
def delete_post(apikey, post_id, username, password, publish):
148
    """blogger.deletePost(api_key, post_id, username, password, 'publish')
149
    => boolean"""
150
    user = authenticate(username, password, 'zinnia.delete_entry')
151
    entry = Entry.objects.get(id=post_id, authors=user)
152
    entry.delete()
153
    return True
156
@xmlrpc_func(returns='struct', args=['string', 'string', 'string'])
157
def get_post(post_id, username, password):
158
    """metaWeblog.getPost(post_id, username, password)
159
    => post structure"""
160
    user = authenticate(username, password)
161
    site = Site.objects.get_current()
162
    return post_structure(Entry.objects.get(id=post_id, authors=user), site)
165
@xmlrpc_func(returns='struct[]', args=['string', 'string', 'string', 'integer'])
166
def get_recent_posts(blog_id, username, password, number):
167
    """metaWeblog.getRecentPosts(blog_id, username, password, number)
168
    => post structure[]"""
169
    user = authenticate(username, password)
170
    site = Site.objects.get_current()
171
    return [post_structure(entry, site) \
172
            for entry in Entry.objects.filter(authors=user)[:number]]
175
@xmlrpc_func(returns='struct[]', args=['string', 'string', 'string'])
176
def get_categories(blog_id, username, password):
177
    """metaWeblog.getCategories(blog_id, username, password)
178
    => category structure[]"""
179
    authenticate(username, password)
180
    site = Site.objects.get_current()
181
    return [category_structure(category, site) \
182
            for category in Category.objects.all()]
185
@xmlrpc_func(returns='string', args=['string', 'string', 'string', 'struct'])
186
def new_category(blog_id, username, password, category_struct):
187
    """wp.newCategory(blog_id, username, password, category)
188
    => category_id"""
189
    authenticate(username, password, 'zinnia.add_category')
190
    category_dict = {'title': category_struct['name'],
191
                     'description': category_struct['description'],
192
                     'slug': category_struct['slug']}
193
    if int(category_struct['parent_id']):
194
        category_dict['parent'] = Category.objects.get(
195
            pk=category_struct['parent_id'])
196
    category = Category.objects.create(**category_dict)
198
    return category.pk
201
@xmlrpc_func(returns='string', args=['string', 'string', 'string',
202
                                     'struct', 'boolean'])
203
def new_post(blog_id, username, password, post, publish):
204
    """metaWeblog.newPost(blog_id, username, password, post, publish)
205
    => post_id"""
206
    user = authenticate(username, password, 'zinnia.add_entry')
207
    if post.get('dateCreated'):
208
        creation_date = datetime.strptime(
209
            post['dateCreated'].value.replace('Z', '').replace('-', ''),
210
            '%Y%m%dT%H:%M:%S')
211
    else:
212
        creation_date = datetime.now()
214
    entry_dict = {'title': post['title'],
215
                  'content': post['description'],
216
                  'excerpt': post.get('mt_excerpt', truncate_words(
217
                      strip_tags(post['description']), 50)),
218
                  'creation_date': creation_date,
219
                  'last_update': creation_date,
220
                  'comment_enabled': post.get('mt_allow_comments', 1) == 1,
221
                  'pingback_enabled': post.get('mt_allow_pings', 1) == 1,
222
                  'featured': post.get('sticky', 0) == 1,
223
                  'tags': 'mt_keywords' in post and post['mt_keywords'] or '',
224
                  'slug': 'wp_slug' in post and post['wp_slug'] or slugify(
225
                      post['title']),
226
                  'password': post.get('wp_password', ''),
227
                  'status': publish and PUBLISHED or DRAFT}
228
    entry = Entry.objects.create(**entry_dict)
230
    author = user
231
    if 'wp_author_id' in post and user.has_perm('zinnia.can_change_author'):
232
        if int(post['wp_author_id']) != user.pk:
233
            author = User.objects.get(pk=post['wp_author_id'])
234
    entry.authors.add(author)
236
    entry.sites.add(Site.objects.get_current())
237
    if 'categories' in post:
238
        entry.categories.add(*[Category.objects.get_or_create(
239
            title=cat, slug=slugify(cat))[0]
240
                               for cat in post['categories']])
242
    return entry.pk
245
@xmlrpc_func(returns='boolean', args=['string', 'string', 'string',
246
                                      'struct', 'boolean'])
247
def edit_post(post_id, username, password, post, publish):
248
    """metaWeblog.editPost(post_id, username, password, post, publish)
249
    => boolean"""
250
    user = authenticate(username, password, 'zinnia.change_entry')
251
    entry = Entry.objects.get(id=post_id, authors=user)
252
    if post.get('dateCreated'):
253
        creation_date = datetime.strptime(
254
            post['dateCreated'].value.replace('Z', '').replace('-', ''),
255
            '%Y%m%dT%H:%M:%S')
256
    else:
257
        creation_date = entry.creation_date
259
    entry.title = post['title']
260
    entry.content = post['description']
261
    entry.excerpt = post.get('mt_excerpt', truncate_words(
262
        strip_tags(post['description']), 50))
263
    entry.creation_date = creation_date
264
    entry.last_update = datetime.now()
265
    entry.comment_enabled = post.get('mt_allow_comments', 1) == 1
266
    entry.pingback_enabled = post.get('mt_allow_pings', 1) == 1
267
    entry.featured = post.get('sticky', 0) == 1
268
    entry.tags = 'mt_keywords' in post and post['mt_keywords'] or ''
269
    entry.slug = 'wp_slug' in post and post['wp_slug'] or slugify(
270
        post['title'])
271
    entry.status = publish and PUBLISHED or DRAFT
272
    entry.password = post.get('wp_password', '')
273
    entry.save()
275
    if 'wp_author_id' in post and user.has_perm('zinnia.can_change_author'):
276
        if int(post['wp_author_id']) != user.pk:
277
            author = User.objects.get(pk=post['wp_author_id'])
278
            entry.authors.clear()
279
            entry.authors.add(author)
281
    if 'categories' in post:
282
        entry.categories.clear()
283
        entry.categories.add(*[Category.objects.get_or_create(
284
            title=cat, slug=slugify(cat))[0]
285
                               for cat in post['categories']])
286
    return True
289
@xmlrpc_func(returns='struct', args=['string', 'string', 'string', 'struct'])
290
def new_media_object(blog_id, username, password, media):
291
    """metaWeblog.newMediaObject(blog_id, username, password, media)
292
    => media structure"""
293
    authenticate(username, password)
294
    path = default_storage.save(os.path.join(UPLOAD_TO, media['name']),
295
                                ContentFile(media['bits'].data))
296
    return {'url': default_storage.url(path)}