Skip to content
This repository has been archived by the owner on Oct 5, 2021. It is now read-only.

Issue212 #222

Merged
merged 7 commits into from
Oct 9, 2017
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
5 changes: 5 additions & 0 deletions django_th/th_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@
'fire': env.bool('DJANGO_TH_FIRE', True),
# if you want to allow the digest feature
'digest_event': env.bool('DJANGO_TH_DIGEST_EVENT', True),
# if sharing_media set to True
# when URL of service contains media
# we download them in the BASE_DIR + '/cache/'
# and upload them through the API of the other service
'sharing_media': env.bool('DJANGO_TH_SHARING_MEDIA', True),
}

TH_SERVICES = (
Expand Down
14 changes: 14 additions & 0 deletions django_th/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,17 @@ def warn_user_and_admin(consumer_provider, service):
mail_admins(title,
body,
fail_silently=False)


def download_image(url):
import requests
import os
cache_dir = os.path.dirname(__file__) + '/cache/'
local_filename = os.path.basename(url)
local_filename = cache_dir + local_filename
r = requests.get(url, stream=True)
with open(local_filename, 'wb') as f:
for chunk in r.iter_content(chunk_size=1024):
if chunk:
f.write(chunk)
return local_filename
144 changes: 80 additions & 64 deletions th_mastodon/my_mastodon.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
# django_th classes
from django_th.services.services import ServicesMgr
from django_th.models import update_result, UserService
from django_th.tools import download_image
from th_mastodon.models import Mastodon

import re

logger = getLogger('django_th.trigger_happy')

Expand Down Expand Up @@ -50,67 +52,55 @@ def read_data(self, **kwargs):

def _get_toots(toot_api, toot_obj, search):
"""
get the toots from mastodon and return the filters to use :
search and count
get the toots from mastodon and return the filters to use

:param toot_obj: from Mastodon model
:param search: filter used for MastodonAPI.search()
:type toot_obj: Object
:type toot_obj: Object ServiceMastodon
:type search: dict
:return: count that limit the quantity of tweet to retrieve,
the filter named search, the tweets
:return: the filter named search, the toots
:rtype: list
"""

max_id = 0 if toot_obj.max_id is None else toot_obj.max_id
since_id = 0 if toot_obj.since_id is None else toot_obj.since_id
# get the toots for a given tag
statuses = ''
count = 100

if toot_obj.tag:
count = 100
search['count'] = count
search['q'] = toot_obj.tag
search['result_type'] = 'recent'
# do a search
statuses = toot_api.search(**search)
# just return the content of te statuses array
statuses = statuses['statuses']

# get the tweets from a given user
elif toot_obj.tooter:
count = 200
search['count'] = count
search['username'] = toot_obj.tooter

search['id'] = toot_obj.tooter
# call the user timeline and get his toot
if toot_obj.fav:
count = 20
search['count'] = 20
statuses = toot_api.favourites(max_id=max_id,
since_id=since_id,
limit=count)
since_id=since_id)
else:
user_id = toot_api.account_search(q=toot_obj.tooter)
statuses = toot_api.account_statuses(
id=toot_obj.tooter,
max_id=max_id,
since_id=since_id,
limit=count)
id=user_id[0]['id'], max_id=toot_obj.max_id,
since_id=toot_obj.since_id)

return count, search, statuses
return search, statuses

if self.token is not None:
kw = {'app_label': 'th_mastodon', 'model_name': 'Mastodon',
'trigger_id': trigger_id}
toot_obj = super(ServiceMastodon, self).read_data(**kw)

us = UserService.objects.get(user=self.user,
token=self.token,
us = UserService.objects.get(token=self.token,
name='ServiceMastodon')
try:
toot_api = MastodonAPI(
client_id=us.client_id,
client_secret=us.client_secret,
access_token=self.token,
api_base_url=us.host
api_base_url=us.host,
)
except ValueError as e:
logger.error(e)
Expand All @@ -121,7 +111,7 @@ def _get_toots(toot_api, toot_obj, search):
search = {'since_id': toot_obj.since_id}

# first request to Mastodon
count, search, statuses = _get_toots(toot_api, toot_obj, search)
search, statuses = _get_toots(toot_api, toot_obj, search)

if len(statuses) > 0:
newest = None
Expand All @@ -133,8 +123,7 @@ def _get_toots(toot_api, toot_obj, search):

since_id = search['since_id'] = statuses[-1]['id'] - 1

count, search, statuses = _get_toots(toot_api, toot_obj,
search)
search, statuses = _get_toots(toot_api, toot_obj, search)

newest = None
if len(statuses) > 0:
Expand All @@ -145,32 +134,25 @@ def _get_toots(toot_api, toot_obj, search):
max_id = s['id'] - 1
toot_name = s['account']['username']
# get the text of the tweet + url to this one
if toot_obj.fav:
url = '{0}/api/v1/statuses/{1}'.format(
self.api_base_url, s['id'])
title = _('Toot Fav from @{}'.format(toot_name))
else:
url = '{0}/api/v1/accounts/{1}/statuses'.format(
self.api_base_url, s['id'])
title = _('Toot from @{}'.format(toot_name))
# Wed Aug 29 17:12:58 +0000 2012
my_date = arrow.get(s['created_at'],
'ddd MMM DD HH:mm:ss Z YYYY')

title = _('Toot from <a href="{}">@{}</a>'.
format(us.host, toot_name))

my_date = arrow.get(s['created_at']).to(
settings.TIME_ZONE)
published = arrow.get(my_date).to(settings.TIME_ZONE)
if date_triggered is not None and \
published is not None and \
now >= published >= date_triggered:
my_toots.append({'title': title,
'content': s['content'],
'link': url,
'link': s['url'],
'my_date': my_date})
# digester
self.send_digest_event(trigger_id, title, url)
self.send_digest_event(trigger_id, title, s['url'])
cache.set('th_mastodon_' + str(trigger_id), my_toots)
Mastodon.objects.filter(trigger_id=trigger_id).update(
since_id=since_id,
max_id=max_id,
count=count)
since_id=since_id, max_id=max_id)
return my_toots

def save_data(self, trigger_id, **data):
Expand All @@ -184,12 +166,16 @@ def save_data(self, trigger_id, **data):
title, content = super(ServiceMastodon, self).save_data(
trigger_id, **data)

# check if we have a 'good' title
if self.title_or_content(title):

content = str("{title} {link}").format(
title=title, link=data.get('link'))

content += self.get_tags(trigger_id)
content = str("{title} {link}").format(title=title,
link=data.get('link'))
content += self.get_tags(trigger_id)
# if not then use the content
else:
content += " " + data.get('link')
content += " " + self.get_tags(trigger_id)

content = self.set_mastodon_content(content)

Expand All @@ -206,16 +192,25 @@ def save_data(self, trigger_id, **data):
)
except ValueError as e:
logger.error(e)
update_result(trigger_id, msg=e, status=False)
status = False
update_result(trigger_id, msg=e, status=status)

try:
toot_api.toot(content)
if settings.DJANGO_TH['sharing_media']:
# do we have a media in the content ?
content, media = self.media_in_content(content)
if media:
# upload the media first
media_ids = toot_api.media_post(media_file=media)
toot_api.status_post(content, media_ids=[media_ids])
else:
toot_api.toot(content)

status = True
except Exception as inst:
logger.critical("Mastodon ERR {}".format(inst))
update_result(trigger_id, msg=inst, status=False)
status = False

update_result(trigger_id, msg=inst, status=status)
return status

def get_tags(self, trigger_id):
Expand All @@ -240,6 +235,38 @@ def get_tags(self, trigger_id):

return tags

def title_or_content(self, title):
"""
If the title always contains 'Tweet from'
drop the title and get 'the content' instead
this allow to have a complet content and not
just a little piece of string
:param title:
:return:
"""
return "Tweet from" not in title

def media_in_content(self, content):
"""
check if the content contains and url of an image
for the moment, check twitter media url
could be elaborate with other service when needed
:param content:
:return:
"""
if 'https://t.co' in content:
content = re.sub(r'https://t.co/(\w+)', '', content)
if 'https://pbs.twimg.com/media/' in content:
m = re.search('https://pbs.twimg.com/media/([\w\-_]+).jpg', content)
url = 'https://pbs.twimg.com/media/{}.jpg'.format(m.group(1))
local_file = download_image(url)

content = re.sub(r'https://pbs.twimg.com/media/([\w\-_]+).jpg', '',
content)

return content, local_file
return content

def set_mastodon_content(self, content):
"""
cleaning content by removing any existing html tag
Expand All @@ -253,17 +280,6 @@ def set_mastodon_content(self, content):

return content

def title_or_content(self, title):
"""
If the title always contains 'New status from'
drop the title and get 'the content' instead
:param title:
:return:
"""
if "New status by" in title:
return False
return True

def auth(self, request):
"""
get the auth of the services
Expand Down
12 changes: 10 additions & 2 deletions th_mastodon/templates/mastodon/edit_provider.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ <h3><span class="glyphicon glyphicon-edit"></span> {% trans 'Edition of the prop
<fieldset>
<legend>{{ context.description }}</legend>
{% csrf_token %}
<div class="form-group{% if form.timeline.errors %} has-error{% endif %}">
{% if form.timeline.errors %}
<div class="col-sm-offset-1 col-sm-6 alert alert-danger" role="alert">{{ form.timeline.errors }}</div>
{% endif %}
<label for="id_timeline" class="col-sm-2 control-label">{% trans "Timeline" %}</label>
<div class="col-sm-6">{{ form.timeline }}</div>
<div class="col-sm-offset-2 col-sm-6">{% trans "Select the scope of the timeline" %}</div>
</div>
<div class="form-group{% if form.tag.errors %} has-error{% endif %}">
{% if form.tag.errors %}
<div class="col-sm-offset-1 col-sm-6 alert alert-danger" role="alert">{{ form.tag.errors }}</div>
Expand All @@ -24,15 +32,15 @@ <h3><span class="glyphicon glyphicon-edit"></span> {% trans 'Edition of the prop
{% endif %}
<label for="id_tooter" class="col-sm-2 control-label">{% trans "Tooter" %}</label>
<div class="col-sm-6">{{ form.tooter }}</div>
<div class="col-sm-offset-2 col-sm-6">{% trans "Put the name of a user you want to get his toots" %}</div>
<div class="col-sm-offset-2 col-sm-6">{% trans "Put the name of a user you want to get his Toots.<br/><i>user@domain.tld</i> for a remote user or just <i>user</i> if you search local toots of this user" %}</div>
</div>
<div class="form-group{% if form.fav.errors %} has-error{% endif %}">
{% if form.fav.errors %}
<div class="col-sm-offset-1 col-sm-6 alert alert-danger" role="alert">{{ form.fav.errors }}</div>
{% endif %}
<label for="id_fav" class="col-sm-2 control-label">{% trans "Save the favorites" %}</label>
<div class="col-sm-6">{{ form.fav }}</div>
<div class="col-sm-offset-2 col-sm-6">{% trans "Save the favorite of the 'tooter' you filled above" %}</div>
<div class="col-sm-6">{% trans "Save the favorite of the 'Tooter' you filled above" %}</div>
</div>

<div class="form-group form-actions">
Expand Down