<commit_before>#!/usr/bin/python
import requests
from os.path import expanduser
import yaml
import json
import sys
import re
from datetime import datetime, timedelta
import glob, os
from collections import Counter

today_date = datetime.now().strftime("%Y-%m-%d")
print "Running on", today_date
config_file = expanduser("~") + '/.bigtime/eileen-config'
config = yaml.safe_load(open(config_file))

logdir = expanduser("~") + '/.bigtime/log/'

days_of_week = ['Monday','Tuesday','Wednesday',
    'Thursday','Friday','Saturday','Sunday']

employee_score = Counter()
employee_days = Counter()
for logfilename in glob.glob(logdir + "timecard-data-*.json"):
    print(logfilename)
    with open(logfilename, 'r') as logfile:
        timecard_data = json.load(logfile)
    logdate = re.sub(logdir + "timecard-data-", '', logfilename)
    logdate = re.sub("\.json",'', logdate)
    print logdate
    #print timecard_data
    employees = {}
    try:
        for record in timecard_data['Data']:
            name = record[4]
            date = record[9]
            if name in employees.keys():
                if date not in employees[name]:
                    employees[name].append(date)
            else:
                employees[name] = [date]
        dayobj = datetime.strptime(logdate, "%Y-%m-%d") - timedelta(days=1)
        day = dayobj.strftime("%Y-%m-%d")
        dow = datetime.strptime(day, "%Y-%m-%d").weekday()
        if dow > 4: # don't show results for weekend days
            continue
        for name in employees.keys():
            if name not in config['ignore']:
                employee_days[name] += 1
                if day in employees[name]:
                    employee_score[name] += 1
    except KeyError:
        print "Bad data in ", logfilename
        pass

report = ""
report_dow = datetime.strptime(today_date, "%Y-%m-%d").weekday()
report += "Timecard Compliance Scores as of "
report += today_date + " " + days_of_week[report_dow] + "\n"
employee_names_to_report = employee_days.keys()
employee_names_to_report.sort()
for employee in employee_names_to_report:
    report +=  employee + " " + \
        str((employee_score[employee] / float(employee_days[employee])) * 100) \
        + "%\n"
print "Slack report: \n" + report

slack_payload = {
    "text":report,
    "channel": config['channel'],
    "icon_emoji": config['emoji'],
    "username": config['username']
    }

'''
if report != "":
    print "sending to slack...", slack_payload
    r = requests.post(config['slack_webhook_url'],
        data = json.dumps(slack_payload))
    print "slack response:", r.text
else:
    print "Nothing to report"
'''
<commit_msg>error handling<commit_after>#!/usr/bin/python
import requests
from os.path import expanduser
import yaml
import json
import sys
import re
from datetime import datetime, timedelta
import glob, os
from collections import Counter

today_date = datetime.now().strftime("%Y-%m-%d")
print "Running on", today_date
config_file = expanduser("~") + '/.bigtime/eileen-config'
config = yaml.safe_load(open(config_file))

logdir = expanduser("~") + '/.bigtime/log/'

days_of_week = ['Monday','Tuesday','Wednesday',
    'Thursday','Friday','Saturday','Sunday']

employee_score = Counter()
employee_days = Counter()
for logfilename in glob.glob(logdir + "timecard-data-*.json"):
    print(logfilename)
    with open(logfilename, 'r') as logfile:
        timecard_data = json.load(logfile)
    logdate = re.sub(logdir + "timecard-data-", '', logfilename)
    logdate = re.sub("\.json",'', logdate)
    print logdate
    #print timecard_data
    employees = {}
    try:
        tc_data = timecard_data['Data']
        for record in tc_data:
            name = record[4]
            date = record[9]
            if name in employees.keys():
                if date not in employees[name]:
                    employees[name].append(date)
            else:
                employees[name] = [date]
        dayobj = datetime.strptime(logdate, "%Y-%m-%d") - timedelta(days=1)
        day = dayobj.strftime("%Y-%m-%d")
        dow = datetime.strptime(day, "%Y-%m-%d").weekday()
        if dow > 4: # don't show results for weekend days
            continue
        for name in employees.keys():
            if name not in config['ignore']:
                employee_days[name] += 1
                if day in employees[name]:
                    employee_score[name] += 1
    except KeyError:
        print "Bad data in ", logfilename
        pass

report = ""
report_dow = datetime.strptime(today_date, "%Y-%m-%d").weekday()
report += "Timecard Compliance Scores as of "
report += today_date + " " + days_of_week[report_dow] + "\n"
employee_names_to_report = employee_days.keys()
employee_names_to_report.sort()
for employee in employee_names_to_report:
    report +=  employee + " " + \
        str((employee_score[employee] / float(employee_days[employee])) * 100) \
        + "%\n"
print "Slack report: \n" + report

slack_payload = {
    "text":report,
    "channel": config['channel'],
    "icon_emoji": config['emoji'],
    "username": config['username']
    }

'''
if report != "":
    print "sending to slack...", slack_payload
    r = requests.post(config['slack_webhook_url'],
        data = json.dumps(slack_payload))
    print "slack response:", r.text
else:
    print "Nothing to report"
'''
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
import collections
import httplib as http
import pytz
import os

from flask import request
from modularodm import Q

from framework.exceptions import HTTPError
from framework.auth.decorators import must_be_logged_in
from framework.forms.utils import sanitize

from website import settings
from website.notifications.emails import notify
from website.notifications.constants import PROVIDERS
from website.models import Guid, Comment
from website.addons.base import GuidFile
from website.project.decorators import must_be_contributor_or_public
from datetime import datetime
from website.project.model import has_anonymous_link
from website.project.views.node import _view_project, n_unread_comments
from website.addons.figshare.exceptions import FigshareIsDraftError
from website.profile.utils import serialize_user

@must_be_contributor_or_public
def view_comments_project(auth, **kwargs):
    """
    Returns information needed to get comments for the total discussion page
    """

    node = kwargs['node'] or kwargs['project']
    page = request.args.get('page', None)
    root_id = node._id if page == Comment.OVERVIEW else None

    if page:
        _update_comments_timestamp(auth, node, page=page, root_id=root_id)

    ret = {
        'comment_target': page or 'total',
        'comment_target_id': root_id
    }
    ret.update(_view_project(node, auth, primary=True, check_files=(not page)))
    return ret

@must_be_contributor_or_public
def view_comments_single(cid, auth, **kwargs):
    """
    Returns information needed to get a single comment and its replies
    """
    node = kwargs['node'] or kwargs['project']
    comment = kwargs_to_comment(cid, auth)
    serialized_comment = serialize_comment(comment, auth)

    from website.addons.wiki.model import NodeWikiPage

    ret = {
        'comment': serialized_comment,
        'comment_target': serialized_comment['page'],
        'comment_target_id': comment.root_target.page_name
        if isinstance(comment.root_target, NodeWikiPage)
        else comment.root_target._id
    }
    ret.update(_view_project(node, auth, primary=True))
    return ret

def resolve_target(node, page, guid):
    if not guid:
        return node
    target = Guid.load(guid)
    if target is None:
        if page == Comment.WIKI:
            return node.get_wiki_page(guid, 1)
        raise HTTPError(http.BAD_REQUEST)
    return target.referent

def update_discussion(target, comments_dict):
    if not getattr(target, 'commented', None) is None:
        for comment in getattr(target, 'commented', []):
            if not (comment.is_deleted or comment.is_hidden):
                comments_dict[comment.user].append(comment)
            update_discussion(comment, comments_dict=comments_dict)
    return comments_dict

def comment_discussion(comments, node, anonymous=False, widget=False):

    comments_dict = collections.defaultdict(list)
    for comment in comments:
        if not (comment.is_deleted or comment.is_hidden):
            comments_dict[comment.user].append(comment)
        if not widget:
            update_discussion(comment, comments_dict=comments_dict)

    sorted_users_frequency = sorted(
        comments_dict.keys(),
        key=lambda item: len(comments_dict[item]),
        reverse=True,
    )

    def get_recency(item):
        most_recent = comments_dict[item][0].date_created
        for comment in comments_dict[item][1:]:
            if comment.date_created > most_recent:
                most_recent = comment.date_created
        return most_recent

    sorted_users_recency = sorted(
        comments_dict.keys(),
        key=get_recency,
        reverse=True,
    )

    return {
        'discussionByFrequency': [
            serialize_user(user, node=node, n_comments=len(comments_dict[user]), anonymous=anonymous)
            for user in sorted_users_frequency
        ],
        'discussionByRecency': [
            serialize_user(user, node=node, n_comments=len(comments_dict[user]), anonymous=anonymous)
            for user in sorted_users_recency
        ]
    }

def serialize_comment(comment, auth, anonymous=False):
    node = comment.node
    if hasattr(comment.root_target, 'page_name'):  # Wiki
        # In case the wiki name is changed
        root_id = comment.root_target.page_name
        title = comment.root_target.page_name
    elif isinstance(comment.root_target, GuidFile):  # File
        root_id = comment.root_target._id
        title = comment.root_target.waterbutler_path
    else:  # Node or comment
        root_id = comment.root_target._id
        title = ''
    return {
        'id': comment._id,
        'author': serialize_user(comment.user, node=node, n_comments=1, anonymous=anonymous),
        'dateCreated': comment.date_created.isoformat(),
        'dateModified': comment.date_modified.isoformat(),
        'page': comment.page,
        'targetId': getattr(comment.target, 'page_name', comment.target._id),
        'rootId': root_id,
        'title': title,
        'provider': comment.root_target.provider if isinstance(comment.root_target, GuidFile) else '',
        'content': comment.content,
        'hasChildren': bool(getattr(comment, 'commented', [])),
        'canEdit': comment.user == auth.user,
        'modified': comment.modified,
        'isDeleted': comment.is_deleted,
        'isHidden': comment.is_hidden,
        'isAbuse': auth.user and auth.user._id in comment.reports,
    }

def kwargs_to_comment(cid, auth, owner=False):
    comment = Comment.load(cid)
    if comment is None:
        raise HTTPError(http.NOT_FOUND)
    if owner:
        if auth.user != comment.user:
            raise HTTPError(http.FORBIDDEN)
    return comment

@must_be_logged_in
@must_be_contributor_or_public
def add_comment(auth, node, **kwargs):

    if not node.comment_level:
        raise HTTPError(http.BAD_REQUEST)

    if not node.can_comment(auth):
        raise HTTPError(http.FORBIDDEN)
    comment_info = request.get_json()
    page = comment_info.get('page')
    guid = comment_info.get('target')
    target = resolve_target(node, page, guid)

    content = comment_info.get('content', None)
    if content:
        content = sanitize(content.strip())
    if not content:
        raise HTTPError(http.BAD_REQUEST)
    if len(content) > settings.COMMENT_MAXLENGTH:
        raise HTTPError(http.BAD_REQUEST)

    comment = Comment.create(
        auth=auth,
        node=node,
        target=target,
        user=auth.user,
        page=page,
        content=content,
    )
    comment.save()

    context = dict(
        gravatar_url=auth.user.gravatar_url,
        content=content,
        page_type=get_page_type(page, node),
        page_title=get_root_target_title(page, comment.root_target),
        provider=get_file_provider(page, comment.root_target),
        target_user=target.user if is_reply(target) else None,
        parent_comment=target.content if is_reply(target) else "",
        url=get_comment_url(node, page, comment.root_target)
    )
    time_now = datetime.utcnow().replace(tzinfo=pytz.utc)
    sent_subscribers = notify(
        uid=node._id,
        event="comments",
        user=auth.user,
        node=node,
        timestamp=time_now,
        **context
    )

    if is_reply(target):
        if target.user and target.user not in sent_subscribers:
            notify(
                uid=target.user._id,
                event='comment_replies',
                user=auth.user,
                node=node,
                timestamp=time_now,
                **context
            )

    return {
        'comment': serialize_comment(comment, auth)
    }, http.CREATED

def get_file_provider(page, root_target):
    if page == Comment.FILES:
        return PROVIDERS[root_target.provider]
    else:
        return ''

def get_page_type(page, node):
    if page == Comment.WIKI:
        return 'wiki'
    elif page == Comment.FILES:
        return 'file'
    elif node.parent_node:
        return 'component'
    else:
        return 'project'

def get_root_target_title(page, root_target):
    if page == Comment.WIKI:
        return root_target.page_name
    elif page == Comment.FILES:
        try:
            root_target.enrich()
        except FigshareIsDraftError:
            pass
        return getattr(root_target, 'name', os.path.split(root_target.waterbutler_path)[1])
    else:
        return ''

def get_comment_url(node, page, root_target):
    if page == Comment.WIKI:
        return node.web_url_for('project_wiki_id_page', wid=root_target._id, _absolute=True)
    elif page == Comment.FILES:
        path = root_target.waterbutler_path[1:]
        return node.web_url_for('addon_view_or_download_file', provider=root_target.provider, path=path, _absolute=True)
    else:
        return node.absolute_url

def is_reply(target):
    return isinstance(target, Comment)

@must_be_contributor_or_public
def list_comments(auth, node, **kwargs):
    anonymous = has_anonymous_link(node, auth)
    page = request.args.get('page')
    guid = request.args.get('target')
    root_id = request.args.get('rootId')
    is_list = request.args.get('isCommentList')
    is_widget = False

    if page == 'total' and not root_id:  # "Total" on discussion page
        comments = list_total_comments(node, auth, 'total')
    elif page == 'total':  # Discussion widget on overview's page
        comments = list_total_comments_widget(node, auth)
        is_widget = True
    elif not root_id:  # Overview/Files/Wiki page on discussion page
        comments = list_total_comments(node, auth, page)
    else:
        target = resolve_target(node, page, guid)
        comments = getattr(target, 'commented', [])

    n_unread = 0
    if node.is_contributor(auth.user):
        if auth.user.comments_viewed_timestamp is None:
            auth.user.comments_viewed_timestamp = {}
            auth.user.save()
        n_unread = n_unread_comments(node, auth.user, page, root_id)

    ret = {
        'comments': [
            serialize_comment(comment, auth, anonymous)
            for comment in comments
        ],
        'nUnread': n_unread
    }
    if is_list:
        discussions = comment_discussion(comments, node, anonymous=anonymous, widget=is_widget)
        ret.update(discussions)

    return ret

def list_total_comments_widget(node, auth):
    comments = list(Comment.find(Q('node', 'eq', node)).sort('date_created'))
    return comments

def list_total_comments(node, auth, page):
    if page == 'total':
        comments = list(Comment.find(Q('node', 'eq', node)).sort('date_created'))
    else:
        comments = list(Comment.find(Q('node', 'eq', node) &
                                Q('page', 'eq', page)).sort('date_created'))

    root_comments = []
    for comment in comments:
        if not isinstance(comment.target, Comment):
            root_comments.append(comment)
    return root_comments

@must_be_logged_in
@must_be_contributor_or_public
def edit_comment(cid, auth, **kwargs):

    comment = kwargs_to_comment(cid, auth, owner=True)

    content = request.get_json().get('content').strip()
    content = sanitize(content)
    if not content:
        raise HTTPError(http.BAD_REQUEST)
    if len(content) > settings.COMMENT_MAXLENGTH:
        raise HTTPError(http.BAD_REQUEST)

    comment.edit(
        content=content,
        auth=auth,
        save=True
    )

    return serialize_comment(comment, auth)

@must_be_logged_in
@must_be_contributor_or_public
def delete_comment(cid, auth, **kwargs):
    comment = kwargs_to_comment(cid, auth, owner=True)
    comment.delete(auth=auth, save=True)

    return {}

@must_be_logged_in
@must_be_contributor_or_public
def undelete_comment(cid, auth, **kwargs):
    comment = kwargs_to_comment(cid, auth, owner=True)
    comment.undelete(auth=auth, save=True)

    return {}

def _update_comments_timestamp(auth, node, page=Comment.OVERVIEW, root_id=None):
    if node.is_contributor(auth.user) and page != 'total':
        user_timestamp = auth.user.comments_viewed_timestamp
        node_timestamp = user_timestamp.get(node._id, None)
        # Handle legacy comments_viewed_timestamp format
        if not node_timestamp:
            user_timestamp[node._id] = dict()
        if node_timestamp and isinstance(node_timestamp, datetime):
            overview_timestamp = user_timestamp[node._id]
            user_timestamp[node._id] = dict()
            user_timestamp[node._id][Comment.OVERVIEW] = overview_timestamp
        timestamps = auth.user.comments_viewed_timestamp[node._id]

        # update node timestamp
        if page == Comment.OVERVIEW:
            timestamps[Comment.OVERVIEW] = datetime.utcnow()
            auth.user.save()
            return {node._id: auth.user.comments_viewed_timestamp[node._id][Comment.OVERVIEW].isoformat()}

        # set up timestamp dictionary for wiki/files page
        if not timestamps.get(page, None):
            timestamps[page] = dict()

        # if updating timestamp on the files/wiki total page...
        if root_id is None:
            return _update_comments_timestamp_total(node, auth, page)

        # if updating timestamp on a specific file/wiki page
        timestamps[page][root_id] = datetime.utcnow()
        auth.user.save()
        return {node._id: auth.user.comments_viewed_timestamp[node._id][page][root_id].isoformat()}
    else:
        return {}

def _update_comments_timestamp_total(node, auth, page):
    from website.addons.wiki.model import NodeWikiPage
    ret = {}
    if page == Comment.FILES:
        for root_target_id in node.commented_files:
            root_target = Guid.load(root_target_id).referent
            if root_target.commented[0].is_hidden:
                continue
            ret = _update_comments_timestamp(auth, node, page, root_target._id)
    elif page == Comment.WIKI:
        root_targets = list(NodeWikiPage.find(Q('node', 'eq', node)))
        for wiki_page in root_targets:
            if hasattr(wiki_page, 'commented'):
                ret = _update_comments_timestamp(auth, node, page, wiki_page.page_name)
    return ret

@must_be_logged_in
@must_be_contributor_or_public
def update_comments_timestamp(auth, node, **kwargs):
    timestamp_info = request.get_json()
    page = timestamp_info.get('page')
    root_id = timestamp_info.get('rootId')
    return _update_comments_timestamp(auth, node, page, root_id)

@must_be_logged_in
@must_be_contributor_or_public
def report_abuse(cid, auth, **kwargs):

    user = auth.user

    comment = kwargs_to_comment(cid, auth)

    category = request.get_json().get('category')
    text = request.get_json().get('text', '')
    if not category:
        raise HTTPError(http.BAD_REQUEST)

    try:
        comment.report_abuse(user, save=True, category=category, text=text)
    except ValueError:
        raise HTTPError(http.BAD_REQUEST)

    return {}

@must_be_logged_in
@must_be_contributor_or_public
def unreport_abuse(cid, auth, **kwargs):
    user = auth.user

    comment = kwargs_to_comment(cid, auth)

    try:
        comment.unreport_abuse(user, save=True)
    except ValueError:
        raise HTTPError(http.BAD_REQUEST)

    return {}
<commit_msg>Discussion overview page should be 'node'<commit_after># -*- coding: utf-8 -*-
import collections
import httplib as http
import pytz
import os

from flask import request
from modularodm import Q

from framework.exceptions import HTTPError
from framework.auth.decorators import must_be_logged_in
from framework.forms.utils import sanitize

from website import settings
from website.notifications.emails import notify
from website.notifications.constants import PROVIDERS
from website.models import Guid, Comment
from website.addons.base import GuidFile
from website.project.decorators import must_be_contributor_or_public
from datetime import datetime
from website.project.model import has_anonymous_link
from website.project.views.node import _view_project, n_unread_comments
from website.addons.figshare.exceptions import FigshareIsDraftError
from website.profile.utils import serialize_user

@must_be_contributor_or_public
def view_comments_project(auth, **kwargs):
    """
    Returns information needed to get comments for the total discussion page
    """

    node = kwargs['node'] or kwargs['project']
    page = request.args.get('page', None)
    if page == 'overview':
        page = Comment.OVERVIEW
    root_id = node._id if page == Comment.OVERVIEW else None

    if page:
        _update_comments_timestamp(auth, node, page=page, root_id=root_id)

    ret = {
        'comment_target': page or 'total',
        'comment_target_id': root_id
    }
    ret.update(_view_project(node, auth, primary=True, check_files=(not page)))
    return ret

@must_be_contributor_or_public
def view_comments_single(cid, auth, **kwargs):
    """
    Returns information needed to get a single comment and its replies
    """
    node = kwargs['node'] or kwargs['project']
    comment = kwargs_to_comment(cid, auth)
    serialized_comment = serialize_comment(comment, auth)

    from website.addons.wiki.model import NodeWikiPage

    ret = {
        'comment': serialized_comment,
        'comment_target': serialized_comment['page'],
        'comment_target_id': comment.root_target.page_name
        if isinstance(comment.root_target, NodeWikiPage)
        else comment.root_target._id
    }
    ret.update(_view_project(node, auth, primary=True))
    return ret

def resolve_target(node, page, guid):
    if not guid:
        return node
    target = Guid.load(guid)
    if target is None:
        if page == Comment.WIKI:
            return node.get_wiki_page(guid, 1)
        raise HTTPError(http.BAD_REQUEST)
    return target.referent

def update_discussion(target, comments_dict):
    if not getattr(target, 'commented', None) is None:
        for comment in getattr(target, 'commented', []):
            if not (comment.is_deleted or comment.is_hidden):
                comments_dict[comment.user].append(comment)
            update_discussion(comment, comments_dict=comments_dict)
    return comments_dict

def comment_discussion(comments, node, anonymous=False, widget=False):

    comments_dict = collections.defaultdict(list)
    for comment in comments:
        if not (comment.is_deleted or comment.is_hidden):
            comments_dict[comment.user].append(comment)
        if not widget:
            update_discussion(comment, comments_dict=comments_dict)

    sorted_users_frequency = sorted(
        comments_dict.keys(),
        key=lambda item: len(comments_dict[item]),
        reverse=True,
    )

    def get_recency(item):
        most_recent = comments_dict[item][0].date_created
        for comment in comments_dict[item][1:]:
            if comment.date_created > most_recent:
                most_recent = comment.date_created
        return most_recent

    sorted_users_recency = sorted(
        comments_dict.keys(),
        key=get_recency,
        reverse=True,
    )

    return {
        'discussionByFrequency': [
            serialize_user(user, node=node, n_comments=len(comments_dict[user]), anonymous=anonymous)
            for user in sorted_users_frequency
        ],
        'discussionByRecency': [
            serialize_user(user, node=node, n_comments=len(comments_dict[user]), anonymous=anonymous)
            for user in sorted_users_recency
        ]
    }

def serialize_comment(comment, auth, anonymous=False):
    node = comment.node
    if hasattr(comment.root_target, 'page_name'):  # Wiki
        # In case the wiki name is changed
        root_id = comment.root_target.page_name
        title = comment.root_target.page_name
    elif isinstance(comment.root_target, GuidFile):  # File
        root_id = comment.root_target._id
        title = comment.root_target.waterbutler_path
    else:  # Node or comment
        root_id = comment.root_target._id
        title = ''
    return {
        'id': comment._id,
        'author': serialize_user(comment.user, node=node, n_comments=1, anonymous=anonymous),
        'dateCreated': comment.date_created.isoformat(),
        'dateModified': comment.date_modified.isoformat(),
        'page': comment.page,
        'targetId': getattr(comment.target, 'page_name', comment.target._id),
        'rootId': root_id,
        'title': title,
        'provider': comment.root_target.provider if isinstance(comment.root_target, GuidFile) else '',
        'content': comment.content,
        'hasChildren': bool(getattr(comment, 'commented', [])),
        'canEdit': comment.user == auth.user,
        'modified': comment.modified,
        'isDeleted': comment.is_deleted,
        'isHidden': comment.is_hidden,
        'isAbuse': auth.user and auth.user._id in comment.reports,
    }

def kwargs_to_comment(cid, auth, owner=False):
    comment = Comment.load(cid)
    if comment is None:
        raise HTTPError(http.NOT_FOUND)
    if owner:
        if auth.user != comment.user:
            raise HTTPError(http.FORBIDDEN)
    return comment

@must_be_logged_in
@must_be_contributor_or_public
def add_comment(auth, node, **kwargs):

    if not node.comment_level:
        raise HTTPError(http.BAD_REQUEST)

    if not node.can_comment(auth):
        raise HTTPError(http.FORBIDDEN)
    comment_info = request.get_json()
    page = comment_info.get('page')
    guid = comment_info.get('target')
    target = resolve_target(node, page, guid)

    content = comment_info.get('content', None)
    if content:
        content = sanitize(content.strip())
    if not content:
        raise HTTPError(http.BAD_REQUEST)
    if len(content) > settings.COMMENT_MAXLENGTH:
        raise HTTPError(http.BAD_REQUEST)

    comment = Comment.create(
        auth=auth,
        node=node,
        target=target,
        user=auth.user,
        page=page,
        content=content,
    )
    comment.save()

    context = dict(
        gravatar_url=auth.user.gravatar_url,
        content=content,
        page_type=get_page_type(page, node),
        page_title=get_root_target_title(page, comment.root_target),
        provider=get_file_provider(page, comment.root_target),
        target_user=target.user if is_reply(target) else None,
        parent_comment=target.content if is_reply(target) else "",
        url=get_comment_url(node, page, comment.root_target)
    )
    time_now = datetime.utcnow().replace(tzinfo=pytz.utc)
    sent_subscribers = notify(
        uid=node._id,
        event="comments",
        user=auth.user,
        node=node,
        timestamp=time_now,
        **context
    )

    if is_reply(target):
        if target.user and target.user not in sent_subscribers:
            notify(
                uid=target.user._id,
                event='comment_replies',
                user=auth.user,
                node=node,
                timestamp=time_now,
                **context
            )

    return {
        'comment': serialize_comment(comment, auth)
    }, http.CREATED

def get_file_provider(page, root_target):
    if page == Comment.FILES:
        return PROVIDERS[root_target.provider]
    else:
        return ''

def get_page_type(page, node):
    if page == Comment.WIKI:
        return 'wiki'
    elif page == Comment.FILES:
        return 'file'
    elif node.parent_node:
        return 'component'
    else:
        return 'project'

def get_root_target_title(page, root_target):
    if page == Comment.WIKI:
        return root_target.page_name
    elif page == Comment.FILES:
        try:
            root_target.enrich()
        except FigshareIsDraftError:
            pass
        return getattr(root_target, 'name', os.path.split(root_target.waterbutler_path)[1])
    else:
        return ''

def get_comment_url(node, page, root_target):
    if page == Comment.WIKI:
        return node.web_url_for('project_wiki_id_page', wid=root_target._id, _absolute=True)
    elif page == Comment.FILES:
        path = root_target.waterbutler_path[1:]
        return node.web_url_for('addon_view_or_download_file', provider=root_target.provider, path=path, _absolute=True)
    else:
        return node.absolute_url

def is_reply(target):
    return isinstance(target, Comment)

@must_be_contributor_or_public
def list_comments(auth, node, **kwargs):
    anonymous = has_anonymous_link(node, auth)
    page = request.args.get('page')
    guid = request.args.get('target')
    root_id = request.args.get('rootId')
    is_list = request.args.get('isCommentList')
    is_widget = False

    if page == 'total' and not root_id:  # "Total" on discussion page
        comments = list_total_comments(node, auth, 'total')
    elif page == 'total':  # Discussion widget on overview's page
        comments = list_total_comments_widget(node, auth)
        is_widget = True
    elif not root_id:  # Overview/Files/Wiki page on discussion page
        comments = list_total_comments(node, auth, page)
    else:
        target = resolve_target(node, page, guid)
        comments = getattr(target, 'commented', [])

    n_unread = 0
    if node.is_contributor(auth.user):
        if auth.user.comments_viewed_timestamp is None:
            auth.user.comments_viewed_timestamp = {}
            auth.user.save()
        n_unread = n_unread_comments(node, auth.user, page, root_id)

    ret = {
        'comments': [
            serialize_comment(comment, auth, anonymous)
            for comment in comments
        ],
        'nUnread': n_unread
    }
    if is_list:
        discussions = comment_discussion(comments, node, anonymous=anonymous, widget=is_widget)
        ret.update(discussions)

    return ret

def list_total_comments_widget(node, auth):
    comments = list(Comment.find(Q('node', 'eq', node)).sort('date_created'))
    return comments

def list_total_comments(node, auth, page):
    if page == 'total':
        comments = list(Comment.find(Q('node', 'eq', node)).sort('date_created'))
    else:
        comments = list(Comment.find(Q('node', 'eq', node) &
                                Q('page', 'eq', page)).sort('date_created'))

    root_comments = []
    for comment in comments:
        if not isinstance(comment.target, Comment):
            root_comments.append(comment)
    return root_comments

@must_be_logged_in
@must_be_contributor_or_public
def edit_comment(cid, auth, **kwargs):

    comment = kwargs_to_comment(cid, auth, owner=True)

    content = request.get_json().get('content').strip()
    content = sanitize(content)
    if not content:
        raise HTTPError(http.BAD_REQUEST)
    if len(content) > settings.COMMENT_MAXLENGTH:
        raise HTTPError(http.BAD_REQUEST)

    comment.edit(
        content=content,
        auth=auth,
        save=True
    )

    return serialize_comment(comment, auth)

@must_be_logged_in
@must_be_contributor_or_public
def delete_comment(cid, auth, **kwargs):
    comment = kwargs_to_comment(cid, auth, owner=True)
    comment.delete(auth=auth, save=True)

    return {}

@must_be_logged_in
@must_be_contributor_or_public
def undelete_comment(cid, auth, **kwargs):
    comment = kwargs_to_comment(cid, auth, owner=True)
    comment.undelete(auth=auth, save=True)

    return {}

def _update_comments_timestamp(auth, node, page=Comment.OVERVIEW, root_id=None):
    if node.is_contributor(auth.user) and page != 'total':
        user_timestamp = auth.user.comments_viewed_timestamp
        node_timestamp = user_timestamp.get(node._id, None)
        # Handle legacy comments_viewed_timestamp format
        if not node_timestamp:
            user_timestamp[node._id] = dict()
        if node_timestamp and isinstance(node_timestamp, datetime):
            overview_timestamp = user_timestamp[node._id]
            user_timestamp[node._id] = dict()
            user_timestamp[node._id][Comment.OVERVIEW] = overview_timestamp
        timestamps = auth.user.comments_viewed_timestamp[node._id]

        # update node timestamp
        if page == Comment.OVERVIEW:
            timestamps[Comment.OVERVIEW] = datetime.utcnow()
            auth.user.save()
            return {node._id: auth.user.comments_viewed_timestamp[node._id][Comment.OVERVIEW].isoformat()}

        # set up timestamp dictionary for wiki/files page
        if not timestamps.get(page, None):
            timestamps[page] = dict()

        # if updating timestamp on the files/wiki total page...
        if root_id is None:
            return _update_comments_timestamp_total(node, auth, page)

        # if updating timestamp on a specific file/wiki page
        timestamps[page][root_id] = datetime.utcnow()
        auth.user.save()
        return {node._id: auth.user.comments_viewed_timestamp[node._id][page][root_id].isoformat()}
    else:
        return {}

def _update_comments_timestamp_total(node, auth, page):
    from website.addons.wiki.model import NodeWikiPage
    ret = {}
    if page == Comment.FILES:
        for root_target_id in node.commented_files:
            root_target = Guid.load(root_target_id).referent
            if root_target.commented[0].is_hidden:
                continue
            ret = _update_comments_timestamp(auth, node, page, root_target._id)
    elif page == Comment.WIKI:
        root_targets = list(NodeWikiPage.find(Q('node', 'eq', node)))
        for wiki_page in root_targets:
            if hasattr(wiki_page, 'commented'):
                ret = _update_comments_timestamp(auth, node, page, wiki_page.page_name)
    return ret

@must_be_logged_in
@must_be_contributor_or_public
def update_comments_timestamp(auth, node, **kwargs):
    timestamp_info = request.get_json()
    page = timestamp_info.get('page')
    root_id = timestamp_info.get('rootId')
    return _update_comments_timestamp(auth, node, page, root_id)

@must_be_logged_in
@must_be_contributor_or_public
def report_abuse(cid, auth, **kwargs):

    user = auth.user

    comment = kwargs_to_comment(cid, auth)

    category = request.get_json().get('category')
    text = request.get_json().get('text', '')
    if not category:
        raise HTTPError(http.BAD_REQUEST)

    try:
        comment.report_abuse(user, save=True, category=category, text=text)
    except ValueError:
        raise HTTPError(http.BAD_REQUEST)

    return {}

@must_be_logged_in
@must_be_contributor_or_public
def unreport_abuse(cid, auth, **kwargs):
    user = auth.user

    comment = kwargs_to_comment(cid, auth)

    try:
        comment.unreport_abuse(user, save=True)
    except ValueError:
        raise HTTPError(http.BAD_REQUEST)

    return {}
<|endoftext|>


<commit_before>#!/usr/bin/python
#
# Setup Settings
#
#==============================================================================#
# Imports
#==============================================================================#

# System Modules
import os
import sys
import glob
import json
from pprint import pprint

# Custom Modules
from lib.send2trash import send2trash # https://github.com/hsoft/send2trash

#==============================================================================#
# Global Variables
#==============================================================================#

mode = ""
mode = "test"

# Name of the settings file
cfg_file = "sync_settings.json"

#==============================================================================#
# Functions
#==============================================================================#

# symlink(current directory, symlink source folder, symlink destination folder )
# Creates a symlink from a file/path to a give path
def symlink(cur, json, src, dst, title, overwrite_all=None):

  json = os.path.dirname(json)
  src = json + "/" + src

  print src

  return

  if (title):
    print title

  # Expand the paths to the current user
  dst = os.path.expanduser(dst)
  src = os.path.join(cur, src)

  # If the target is an existing file or folder
  # Ask to overwrite it or to skip it
  if any( [os.path.isfile(dst), os.path.isdir(dst), os.path.islink(dst) ] ):

    # TODO 001: Remove this unecessary if condition

    # When overwrite_all is "y" or in testing mode
    # Overwrite the file
    if any ( [overwrite_all] ):

      overwrite_all = 1

    else:

      print "File " + dst + " already exists."

      # Check the prompt value for
      #
      # a: Overwrite all files and don't ask anymore if files should be overwritten
      # y: Continue the function and overwrite
      # n: Exit the function and don't overwrite
      #
      # On any other input repeat the prompt

      prompt = ""

      while all ([
                   prompt != "y",
                   prompt != "n",
                   prompt != "a"
                  ]):
        prompt = raw_input("Overwrite (y/n/a): ")

      if (prompt == "a"):
        overwrite_all = 1 # Overwrite All
      elif (prompt == "n"):
        return # Exit
      elif (prompt == "y"):
        pass # Overwrite only this file

  # Trash the resulting destination file or dir
  # And delete symlinks so they don't crowd the trashbin
  if (os.path.islink(dst)):
    os.unlink(dst)
  else:
    send2trash(dst)

  # Create the symlink
  os.symlink(src, dst)

  # Print the symlink creation information
  print "Creating SymLink: "
  print "  Src: " + src
  print "  Dst: " + dst + "\n"

  return overwrite_all

#==============================================================================#
# Main
#==============================================================================#

def main(argv=None):

  #----------------------------------------------------------------------------#
  # Variables
  #----------------------------------------------------------------------------#

  # If this is true all existing files will be overwriteen
  overwrite_all = 0

  # Path with the settings
  settings_dir = "~/Settings"
  settings_dir = os.path.expanduser(settings_dir)

  # Check if there is either a symlink or a dir ~/Settings
  # After that check if there is a Settings dir in the parent dir of the script
  # If none of these exist, exit the script
  if (os.path.islink(settings_dir)):
    settings_dir = (os.path.realpath(os.path.expanduser(settings_dir))) # Expand the user and find the symlink target path
  elif (os.path.isdir(settings_dir)):
    settings_dir = (os.path.expanduser(settings_dir)) # Expand the user and find the symlink target path
  else:
    print "No Settings folder found in either ~/ or the script dir!"
    return

  # Get all sync setting files
  # Or just the test folder in test mode
  if (mode != "test"):
    cfg  = glob.glob(settings_dir + '*/' + cfg_file)
    cfg += glob.glob(settings_dir + '*/*/' + cfg_file)
    cfg += glob.glob(settings_dir + '*/*/*/' + cfg_file)
    cfg += glob.glob(settings_dir + '*/*/*/*' + cfg_file)
  else:
    cfg = [settings_dir + '/test/' + cfg_file]

  # If there aren't any config files exit the script
  if not(cfg):
    print ("No %s files found!" % cfg_file)
    return

  #----------------------------------------------------------------------------#
  # Symlink Iteration
  #----------------------------------------------------------------------------#

  # Loop through the configuration files and create the symlinks
  for x in cfg:

    # Load the data from the json files into data
    json_data = open(x)
    data = json.load(json_data)
    json_data.close()

    for d in data["symlink"]:
      overwrite_all = symlink(settings_dir, x, d["src"], d["dst"], d["title"], overwrite_all)

# Advanced main function call
# http://www.artima.com/weblogs/viewpost.jsp?thread=4829
if __name__ == "__main__":
  sys.exit(main())
  pass<commit_msg>Getting the correct path<commit_after>#!/usr/bin/python
#
# Setup Settings
#
#==============================================================================#
# Imports
#==============================================================================#

# System Modules
import os
import sys
import glob
import json
from pprint import pprint

# Custom Modules
from lib.send2trash import send2trash # https://github.com/hsoft/send2trash

#==============================================================================#
# Global Variables
#==============================================================================#

mode = ""
mode = "test"

# Name of the settings file
cfg_file = "sync_settings.json"

#==============================================================================#
# Functions
#==============================================================================#

# symlink(current directory, symlink source folder, symlink destination folder )
# Creates a symlink from a file/path to a give path
def symlink(cur, json, src, dst, title, overwrite_all=None):

  if (title):
    print title

  # Grab the path from the json parent dir
  json = os.path.dirname(json)
  src = json + "/" + src

  # Expand the paths to the current user
  dst = os.path.expanduser(dst)

  # If the target is an existing file or folder
  # Ask to overwrite it or to skip it
  if any( [os.path.isfile(dst), os.path.isdir(dst), os.path.islink(dst)] ):

    # TODO 001: Remove this unecessary if condition

    # When overwrite_all is "y" or in testing mode
    # Overwrite the file
    if any ( [overwrite_all] ):

      overwrite_all = 1

    else:

      print "File " + dst + " already exists."

      # Check the prompt value for
      #
      # a: Overwrite all files and don't ask anymore if files should be overwritten
      # y: Continue the function and overwrite
      # n: Exit the function and don't overwrite
      #
      # On any other input repeat the prompt

      prompt = ""

      while all ([
                   prompt != "y",
                   prompt != "n",
                   prompt != "a"
                  ]):
        prompt = raw_input("Overwrite (y/n/a): ")

      if (prompt == "a"):
        overwrite_all = 1 # Overwrite All
      elif (prompt == "n"):
        return # Exit
      elif (prompt == "y"):
        pass # Overwrite only this file

  # Trash the resulting destination file or dir
  # And delete symlinks so they don't crowd the trashbin
  if (os.path.islink(dst)):
    os.unlink(dst)
  else:
    send2trash(dst)

  # Create the symlink
  os.symlink(src, dst)

  # Print the symlink creation information
  print "Creating SymLink: "
  print "  Src: " + src
  print "  Dst: " + dst + "\n"

  return overwrite_all

#==============================================================================#
# Main
#==============================================================================#

def main(argv=None):

  #----------------------------------------------------------------------------#
  # Variables
  #----------------------------------------------------------------------------#

  # If this is true all existing files will be overwriteen
  overwrite_all = 0

  # Path with the settings
  settings_dir = "~/Settings"
  settings_dir = os.path.expanduser(settings_dir)

  # Check if there is either a symlink or a dir ~/Settings
  # After that check if there is a Settings dir in the parent dir of the script
  # If none of these exist, exit the script
  if (os.path.islink(settings_dir)):
    settings_dir = (os.path.realpath(os.path.expanduser(settings_dir))) # Expand the user and find the symlink target path
  elif (os.path.isdir(settings_dir)):
    settings_dir = (os.path.expanduser(settings_dir)) # Expand the user and find the symlink target path
  else:
    print "No Settings folder found in either ~/ or the script dir!"
    return

  # Get all sync setting files
  # Or just the test folder in test mode
  if (mode != "test"):
    cfg  = glob.glob(settings_dir + '*/' + cfg_file)
    cfg += glob.glob(settings_dir + '*/*/' + cfg_file)
    cfg += glob.glob(settings_dir + '*/*/*/' + cfg_file)
    cfg += glob.glob(settings_dir + '*/*/*/*' + cfg_file)
  else:
    cfg = [settings_dir + '/test/' + cfg_file]

  # If there aren't any config files exit the script
  if not(cfg):
    print ("No %s files found!" % cfg_file)
    return

  #----------------------------------------------------------------------------#
  # Symlink Iteration
  #----------------------------------------------------------------------------#

  # Loop through the configuration files and create the symlinks
  for x in cfg:

    # Load the data from the json files into data
    json_data = open(x)
    data = json.load(json_data)
    json_data.close()

    for d in data["symlink"]:
      overwrite_all = symlink(settings_dir, x, d["src"], d["dst"], d["title"], overwrite_all)

# Advanced main function call
# http://www.artima.com/weblogs/viewpost.jsp?thread=4829
if __name__ == "__main__":
  sys.exit(main())
  pass<|endoftext|>


<commit_before># This file is part of Workout Manager.
#
# Workout Manager is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Workout Manager is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License

import json

from django.core.urlresolvers import reverse

from wger.exercises.models import Exercise

from wger.manager.tests.testcase import WorkoutManagerTestCase
from wger.manager.tests.testcase import WorkoutManagerDeleteTestCase

class ExerciseIndexTestCase(WorkoutManagerTestCase):

    def exercise_index(self, editor=False):
        '''
        Tests the exercise overview page
        '''

        response = self.client.get(reverse('wger.exercises.views.exercise_overview'))

        # Page exists
        self.assertEqual(response.status_code, 200)

        # Correct tab is selected
        self.assertEqual(response.context['active_tab'], 'exercises')

        # Correct categories are shown
        category_1 = response.context['categories'][0]
        self.assertEqual(category_1.id, 2)
        self.assertEqual(category_1.name, "Another category")

        category_2 = response.context['categories'][1]
        self.assertEqual(category_2.id, 3)
        self.assertEqual(category_2.name, "Yet another category")

        # Correct exercises in the categories
        exercises_1 = category_1.exercise_set.all()
        exercise_1 = exercises_1[0]
        exercise_2 = exercises_1[1]
        self.assertEqual(exercise_1.id, 2)
        self.assertEqual(exercise_1.name, "A very cool exercise")

        self.assertEqual(exercise_2.id, 1)
        self.assertEqual(exercise_2.name, "An exercise")

        # Only authorized users see the edit links
        if editor:
            self.assertContains(response, 'Add new exercise')
            self.assertContains(response, 'Edit category')
            self.assertContains(response, 'Delete category')
            self.assertContains(response, 'Add category')
        else:
            self.assertNotContains(response, 'Add new exercise')
            self.assertNotContains(response, 'Edit category')
            self.assertNotContains(response, 'Delete category')
            self.assertNotContains(response, 'Add category')

    def test_exercise_index_editor(self):
        '''
        Tests the exercise overview page as a logged in user with editor rights
        '''

        self.user_login('admin')
        self.exercise_index(editor=True)

    def test_exercise_index_non_editor(self):
        '''
        Tests the exercise overview page as a logged in user without editor rights
        '''

        self.user_login('test')
        self.exercise_index(editor=False)

    def test_exercise_index_logged_out(self):
        '''
        Tests the exercise overview page as an anonymous (logged out) user
        '''

        self.exercise_index(editor=False)

class ExerciseDetailTestCase(WorkoutManagerTestCase):
    '''
    Tests the exercise details page
    '''

    def exercise_detail(self, editor=False):
        '''
        Tests the exercise details page
        '''

        response = self.client.get(reverse('wger.exercises.views.exercise_view', kwargs={'id': 1}))
        self.assertEqual(response.status_code, 200)

        # Correct tab is selected
        self.assertEqual(response.context['active_tab'], 'exercises')

        # Exercise loaded correct muscles
        exercise_1 = response.context['exercise']
        self.assertEqual(exercise_1.id, 1)

        muscles = exercise_1.muscles.all()
        muscle_1 = muscles[0]
        muscle_2 = muscles[1]

        self.assertEqual(muscle_1.id, 1)
        self.assertEqual(muscle_2.id, 2)

        # Only authorized users see the edit links
        if editor:
            self.assertContains(response, 'Edit')
            self.assertContains(response, 'Delete')
            self.assertContains(response, 'Add new comment')

        else:
            self.assertNotContains(response, 'Edit')
            self.assertNotContains(response, 'Delete')
            self.assertNotContains(response, 'Add new comment')

        # Ensure that non-existent exercises throw a 404.
        response = self.client.get(reverse('wger.exercises.views.exercise_view', kwargs={'id': 42}))
        self.assertEqual(response.status_code, 404)

    def test_exercise_detail_editor(self):
        '''
        Tests the exercise details page as a logged in user with editor rights
        '''

        self.user_login('admin')
        self.exercise_detail(editor=True)

    def test_exercise_detail_non_editor(self):
        '''
        Tests the exercise details page as a logged in user without editor rights
        '''

        self.user_login('test')
        self.exercise_detail(editor=False)

    def test_exercise_detail_logged_out(self):
        '''
        Tests the exercise details page as an anonymous (logged out) user
        '''

        self.exercise_detail(editor=False)

class ExercisesTestCase(WorkoutManagerTestCase):
    '''
    Exercise test case
    '''

    def add_exercise_user_fail(self):
        '''
        Helper function to test adding exercises by users that aren't authorized
        '''

        # Add an exercise
        count_before = Exercise.objects.count()
        response = self.client.post(reverse('exercise-add'),
                                    {'category': 2,
                                    'name': 'my test exercise',
                                    'muscles': [1, 2]})
        count_after = Exercise.objects.count()

        # Exercise was not added
        self.assertEqual(count_before, count_after)
        self.assertTrue('login' in response['location'])

    def test_add_exercise_user_no_rights(self):
        '''
        Tests adding an exercise with a user without enough rights to do this
        '''

        self.user_login('test')
        self.add_exercise_user_fail()
        self.user_logout()

    def test_add_exercise_no_user(self):
        '''
        Tests adding an exercise with a logged out (anonymous) user
        '''

        self.user_logout()
        self.add_exercise_user_fail()
        self.user_logout()

    def test_add_exercise_administrator_user(self):
        '''
        Tests adding/editing an exercise with a user with enough rights to do this
        '''

        # Log in as 'admin'
        self.user_login()

        # Add an exercise
        count_before = Exercise.objects.count()
        response = self.client.post(reverse('exercise-add'),
                                    {'category': 2,
                                    'name': 'my test exercise',
                                    'muscles': [1, 2]})
        count_after = Exercise.objects.count()
        self.assertEqual(response.status_code, 302)
        new_location = response['Location']
        self.assertEqual(count_before + 1, count_after, 'Exercise was not added')

        response = self.client.get(new_location)
        exercise_id = response.context['exercise'].id

        # Exercise was saved
        response = self.client.get(reverse('wger.exercises.views.exercise_view',
                                   kwargs={'id': exercise_id}))
        self.assertEqual(response.status_code, 200)

        # Navigation tab
        self.assertEqual(response.context['active_tab'], 'exercises')

        exercise_1 = Exercise.objects.get(pk=exercise_id)
        self.assertEqual(exercise_1.name, 'my test exercise')

        # Wrong category - adding
        response = self.client.post(reverse('exercise-add'),
                                    {'category': 111,
                                    'name': 'my test exercise',
                                    'muscles': [1, 2]})
        self.assertTrue(response.context['form'].errors['category'])

        # Wrong category - editing
        response = self.client.post(reverse('exercise-edit', kwargs={'pk': '1'}),
                                    {'category': 111,
                                    'name': 'my test exercise',
                                    'muscles': [1, 2]})
        self.assertTrue(response.context['form'].errors['category'])

        # No muscles - adding
        response = self.client.post(reverse('exercise-add'),
                                    {'category': 1,
                                    'name': 'my test exercise',
                                    'muscles': []})
        self.assertTrue(response.context['form'].errors['muscles'])

        # No muscles - editing
        response = self.client.post(reverse('exercise-edit', kwargs={'pk': '1'}),
                                    {'category': 1,
                                    'name': 'my test exercise',
                                    'muscles': []})
        self.assertTrue(response.context['form'].errors['muscles'])
        self.user_logout()

    def search_exercise(self, fail=True):
        '''
        Helper function to test searching for exercises
        '''

        # Search for exercises (1 hit, "A very cool exercise")
        response = self.client.get(reverse('wger.exercises.views.exercise_search') + '?term=cool')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(len(response.context['exercises']), 1)
        self.assertEqual(response.context['exercises'][0].name, 'A very cool exercise')

        kwargs = {'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'}

        # AJAX-Search for exercises (1 hit, "A very cool exercise")
        response = self.client.get(reverse('wger.exercises.views.exercise_search') +
                                   '?term=cool', **kwargs)
        self.assertEqual(response.status_code, 200)
        result = json.loads(response.content)
        self.assertEqual(len(result), 1)
        self.assertEqual(result[0]['value'], 'A very cool exercise')

    def test_search_exercise_anonymous(self):
        '''
        Test deleting an exercise by an anonymous user
        '''

        self.search_exercise()

    def test_search_exercise_unauthorized(self):
        '''
        Test deleting an exercise by an unauthorized user
        '''

        self.user_login('test')
        self.search_exercise()
        self.user_logout()

    def test_search_exercise_authorized(self):
        '''
        Test deleting an exercise by an authorized user
        '''

        self.user_login()
        self.search_exercise(fail=False)
        self.user_logout()

class DeleteExercisesTestCase(WorkoutManagerDeleteTestCase):
    '''
    Exercise test case
    '''

    object_class = Exercise
    url = 'exercise-delete'
    pk = 2
    user_success = 'admin'
    user_fail = 'test'
<commit_msg>Simplify exercise testcase (same result for aministrator and regular user)<commit_after># This file is part of Workout Manager.
#
# Workout Manager is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Workout Manager is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License

import json

from django.core.urlresolvers import reverse

from wger.exercises.models import Exercise

from wger.manager.tests.testcase import WorkoutManagerTestCase
from wger.manager.tests.testcase import WorkoutManagerDeleteTestCase

class ExerciseIndexTestCase(WorkoutManagerTestCase):

    def exercise_index(self, editor=False):
        '''
        Tests the exercise overview page
        '''

        response = self.client.get(reverse('wger.exercises.views.exercise_overview'))

        # Page exists
        self.assertEqual(response.status_code, 200)

        # Correct tab is selected
        self.assertEqual(response.context['active_tab'], 'exercises')

        # Correct categories are shown
        category_1 = response.context['categories'][0]
        self.assertEqual(category_1.id, 2)
        self.assertEqual(category_1.name, "Another category")

        category_2 = response.context['categories'][1]
        self.assertEqual(category_2.id, 3)
        self.assertEqual(category_2.name, "Yet another category")

        # Correct exercises in the categories
        exercises_1 = category_1.exercise_set.all()
        exercise_1 = exercises_1[0]
        exercise_2 = exercises_1[1]
        self.assertEqual(exercise_1.id, 2)
        self.assertEqual(exercise_1.name, "A very cool exercise")

        self.assertEqual(exercise_2.id, 1)
        self.assertEqual(exercise_2.name, "An exercise")

        # Only authorized users see the edit links
        if editor:
            self.assertContains(response, 'Add new exercise')
            self.assertContains(response, 'Edit category')
            self.assertContains(response, 'Delete category')
            self.assertContains(response, 'Add category')
        else:
            self.assertNotContains(response, 'Add new exercise')
            self.assertNotContains(response, 'Edit category')
            self.assertNotContains(response, 'Delete category')
            self.assertNotContains(response, 'Add category')

    def test_exercise_index_editor(self):
        '''
        Tests the exercise overview page as a logged in user with editor rights
        '''

        self.user_login('admin')
        self.exercise_index(editor=True)

    def test_exercise_index_non_editor(self):
        '''
        Tests the exercise overview page as a logged in user without editor rights
        '''

        self.user_login('test')
        self.exercise_index(editor=False)

    def test_exercise_index_logged_out(self):
        '''
        Tests the exercise overview page as an anonymous (logged out) user
        '''

        self.exercise_index(editor=False)

class ExerciseDetailTestCase(WorkoutManagerTestCase):
    '''
    Tests the exercise details page
    '''

    def exercise_detail(self, editor=False):
        '''
        Tests the exercise details page
        '''

        response = self.client.get(reverse('wger.exercises.views.exercise_view', kwargs={'id': 1}))
        self.assertEqual(response.status_code, 200)

        # Correct tab is selected
        self.assertEqual(response.context['active_tab'], 'exercises')

        # Exercise loaded correct muscles
        exercise_1 = response.context['exercise']
        self.assertEqual(exercise_1.id, 1)

        muscles = exercise_1.muscles.all()
        muscle_1 = muscles[0]
        muscle_2 = muscles[1]

        self.assertEqual(muscle_1.id, 1)
        self.assertEqual(muscle_2.id, 2)

        # Only authorized users see the edit links
        if editor:
            self.assertContains(response, 'Edit')
            self.assertContains(response, 'Delete')
            self.assertContains(response, 'Add new comment')

        else:
            self.assertNotContains(response, 'Edit')
            self.assertNotContains(response, 'Delete')
            self.assertNotContains(response, 'Add new comment')

        # Ensure that non-existent exercises throw a 404.
        response = self.client.get(reverse('wger.exercises.views.exercise_view', kwargs={'id': 42}))
        self.assertEqual(response.status_code, 404)

    def test_exercise_detail_editor(self):
        '''
        Tests the exercise details page as a logged in user with editor rights
        '''

        self.user_login('admin')
        self.exercise_detail(editor=True)

    def test_exercise_detail_non_editor(self):
        '''
        Tests the exercise details page as a logged in user without editor rights
        '''

        self.user_login('test')
        self.exercise_detail(editor=False)

    def test_exercise_detail_logged_out(self):
        '''
        Tests the exercise details page as an anonymous (logged out) user
        '''

        self.exercise_detail(editor=False)

class ExercisesTestCase(WorkoutManagerTestCase):
    '''
    Exercise test case
    '''

    def add_exercise_user_fail(self):
        '''
        Helper function to test adding exercises by users that aren't authorized
        '''

        # Add an exercise
        count_before = Exercise.objects.count()
        response = self.client.post(reverse('exercise-add'),
                                    {'category': 2,
                                    'name': 'my test exercise',
                                    'muscles': [1, 2]})
        count_after = Exercise.objects.count()

        # Exercise was not added
        self.assertEqual(count_before, count_after)
        self.assertTrue('login' in response['location'])

    def test_add_exercise_user_no_rights(self):
        '''
        Tests adding an exercise with a user without enough rights to do this
        '''

        self.user_login('test')
        self.add_exercise_user_fail()
        self.user_logout()

    def test_add_exercise_no_user(self):
        '''
        Tests adding an exercise with a logged out (anonymous) user
        '''

        self.user_logout()
        self.add_exercise_user_fail()
        self.user_logout()

    def test_add_exercise_administrator_user(self):
        '''
        Tests adding/editing an exercise with a user with enough rights to do this
        '''

        # Log in as 'admin'
        self.user_login()

        # Add an exercise
        count_before = Exercise.objects.count()
        response = self.client.post(reverse('exercise-add'),
                                    {'category': 2,
                                    'name': 'my test exercise',
                                    'muscles': [1, 2]})
        count_after = Exercise.objects.count()
        self.assertEqual(response.status_code, 302)
        new_location = response['Location']
        self.assertEqual(count_before + 1, count_after, 'Exercise was not added')

        response = self.client.get(new_location)
        exercise_id = response.context['exercise'].id

        # Exercise was saved
        response = self.client.get(reverse('wger.exercises.views.exercise_view',
                                   kwargs={'id': exercise_id}))
        self.assertEqual(response.status_code, 200)

        # Navigation tab
        self.assertEqual(response.context['active_tab'], 'exercises')

        exercise_1 = Exercise.objects.get(pk=exercise_id)
        self.assertEqual(exercise_1.name, 'my test exercise')

        # Wrong category - adding
        response = self.client.post(reverse('exercise-add'),
                                    {'category': 111,
                                    'name': 'my test exercise',
                                    'muscles': [1, 2]})
        self.assertTrue(response.context['form'].errors['category'])

        # Wrong category - editing
        response = self.client.post(reverse('exercise-edit', kwargs={'pk': '1'}),
                                    {'category': 111,
                                    'name': 'my test exercise',
                                    'muscles': [1, 2]})
        self.assertTrue(response.context['form'].errors['category'])

        # No muscles - adding
        response = self.client.post(reverse('exercise-add'),
                                    {'category': 1,
                                    'name': 'my test exercise',
                                    'muscles': []})
        self.assertTrue(response.context['form'].errors['muscles'])

        # No muscles - editing
        response = self.client.post(reverse('exercise-edit', kwargs={'pk': '1'}),
                                    {'category': 1,
                                    'name': 'my test exercise',
                                    'muscles': []})
        self.assertTrue(response.context['form'].errors['muscles'])
        self.user_logout()

    def search_exercise(self, fail=True):
        '''
        Helper function to test searching for exercises
        '''

        # Search for exercises (1 hit, "A very cool exercise")
        response = self.client.get(reverse('wger.exercises.views.exercise_search') + '?term=cool')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(len(response.context['exercises']), 1)
        self.assertEqual(response.context['exercises'][0].name, 'A very cool exercise')

        kwargs = {'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'}

        # AJAX-Search for exercises (1 hit, "A very cool exercise")
        response = self.client.get(reverse('wger.exercises.views.exercise_search') +
                                   '?term=cool', **kwargs)
        self.assertEqual(response.status_code, 200)
        result = json.loads(response.content)
        self.assertEqual(len(result), 1)
        self.assertEqual(result[0]['value'], 'A very cool exercise')

    def test_search_exercise_anonymous(self):
        '''
        Test deleting an exercise by an anonymous user
        '''

        self.search_exercise()

    def test_search_exercise_logged_in(self):
        '''
        Test deleting an exercise by a logged in user
        '''

        self.user_login('test')
        self.search_exercise()

class DeleteExercisesTestCase(WorkoutManagerDeleteTestCase):
    '''
    Exercise test case
    '''

    object_class = Exercise
    url = 'exercise-delete'
    pk = 2
    user_success = 'admin'
    user_fail = 'test'
<|endoftext|>


<commit_before>from wikitrivia.article import Article

import click
import json

@click.command()
@click.argument('title')
@click.option('--output', default=False, help='Output to JSON file')
def generate_trivia(title, output):
    """Generates trivia questions from wikipedia articles"""
    article = Article(title=title)
    questions = article.generate_trivia_sentences()

    if output:
      with open('foo.json', 'w') as json_file:
        json.dump(questions, json_file)
        click.echo('Output stored in foo.json')
    else:
      click.echo(questions)

if __name__ == '__main__':
    generate_trivia()
<commit_msg>Changing answers to answer<commit_after>from wikitrivia.article import Article

import click
import json

@click.command()
@click.argument('title')
@click.option('--output', default=False, help='Output to JSON file')
def generate_trivia(title, output):
    """Generates trivia questions from wikipedia articles"""
    article = Article(title=title)
    questions = article.generate_trivia_sentences()

    if output:
      with open(output, 'w') as json_file:
        json.dump(questions, json_file)
        click.echo('Output stored in {0}'.format(output))
    else:
      click.echo(questions)

if __name__ == '__main__':
    generate_trivia()
<|endoftext|>


<commit_before>#   Copyright (c) 2006-2007 Open Source Applications Foundation
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.

import logging, os, sys, tempfile, shutil

def findInPath(fileName, path=os.environ['PATH']):
    dirs = path.split(os.pathsep)
    for dir in dirs:
        if os.path.isfile(os.path.join(dir, fileName)):
            return os.path.join(dir, fileName)
        if os.name == 'nt' or sys.platform == 'cygwin':
            if os.path.isfile(os.path.join(dir, fileName + ".exe")):
                return os.path.join(dir, fileName + ".exe")
    return None

CONSOLE_LOG_LEVEL = logging.INFO
FILE_LOG_LEVEL    = logging.INFO

SERVER_HTTP_PORT = 4444
PLATFORM         = sys.platform
WINDMILL_PATH    = os.path.dirname(os.path.abspath(os.path.dirname(__file__)))
JS_PATH          = os.path.join(WINDMILL_PATH, 'js')

TEST_URL  = 'http://www.google.com'
TEST_FILE = None
TEST_DIR  = None

USECODE             = False
EXIT_ON_DONE        = False
CONTINUE_ON_FAILURE = False
ENABLE_PDB          = False
BROWSER_DEBUGGING   = False
START_FIREFOX       = False

PYTHON_TEST_FRAME = False
PYTHON_TEST_FILE  = None

# Browser prefs

# Mozilla prefs
MOZILLA_CREATE_NEW_PROFILE     = True
MOZILLA_REMOVE_PROFILE_ON_EXIT = True

MOZILLA_PROFILE_PATH = tempfile.mkdtemp(suffix='.windmill')

while MOZILLA_PROFILE_PATH.find('-') is not -1:
    shutil.rmtree(MOZILLA_PROFILE_PATH)
    MOZILLA_PROFILE_PATH = tempfile.mkdtemp(suffix='.windmill')

if PLATFORM == 'darwin':
    firefoxApp = os.path.join('/Applications', 'Firefox.app')
    firefoxDir = os.path.join(os.path.expanduser('~/'), firefoxApp)

    if not os.path.isdir(firefoxDir):
        firefoxDir = firefoxApp

    MOZILLA_DEFAULT_PROFILE = os.path.join(firefoxDir, 'Contents', 'MacOS', 'defaults', 'profile')
    MOZILLA_BINARY          = os.path.join(firefoxDir, 'Contents', 'MacOS', 'firefox-bin')

elif sys.platform == 'linux2':
    firefoxBin = findInPath('firefox')

    if firefoxBin is not None and os.path.isfile(firefoxBin):
        MOZILLA_BINARY = firefoxBin

    if os.path.isdir('/usr/share/firefox/defaults/profile'):
        MOZILLA_DEFAULT_PROFILE = '/usr/share/firefox/defaults/profile'

elif os.name == 'nt' or sys.platform == 'cygwin':
    IE_BINARY  = findInPath('iexplore')
    firefoxBin = findInPath('firefox')

    if firefoxBin is None:
        try:
            firefoxBin = os.path.join(os.environ['ProgramFiles'], 'Mozilla Firefox', 'firefox.exe')
        except:
            firefoxBin = None

    if firefoxBin is not None and os.path.isfile(firefoxBin):
        firefoxDir = os.path.dirname(firefoxBin)

        MOZILLA_BINARY          = firefoxBin
        MOZILLA_DEFAULT_PROFILE = os.path.join(firefoxDir, 'defaults', 'profile')

if __name__ == '__main__':
    if '--test' in sys.argv:
        print 'running on           ', PLATFORM
        print 'we are at            ', WINDMILL_PATH
        print 'our JS is at         ', JS_PATH
        print 'firefox is at        ', MOZILLA_BINARY
        print 'default profile is at', MOZILLA_DEFAULT_PROFILE

<commit_msg>Fixed leading / bug in the find-out-where-firefox-lives-on-mac code bug by sprout, clue-stick by mikeal<commit_after>#   Copyright (c) 2006-2007 Open Source Applications Foundation
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.

import logging, os, sys, tempfile, shutil

def findInPath(fileName, path=os.environ['PATH']):
    dirs = path.split(os.pathsep)
    for dir in dirs:
        if os.path.isfile(os.path.join(dir, fileName)):
            return os.path.join(dir, fileName)
        if os.name == 'nt' or sys.platform == 'cygwin':
            if os.path.isfile(os.path.join(dir, fileName + ".exe")):
                return os.path.join(dir, fileName + ".exe")
    return None

CONSOLE_LOG_LEVEL = logging.INFO
FILE_LOG_LEVEL    = logging.INFO

SERVER_HTTP_PORT = 4444
PLATFORM         = sys.platform
WINDMILL_PATH    = os.path.dirname(os.path.abspath(os.path.dirname(__file__)))
JS_PATH          = os.path.join(WINDMILL_PATH, 'js')

TEST_URL  = 'http://www.google.com'
TEST_FILE = None
TEST_DIR  = None

USECODE             = False
EXIT_ON_DONE        = False
CONTINUE_ON_FAILURE = False
ENABLE_PDB          = False
BROWSER_DEBUGGING   = False
START_FIREFOX       = False

PYTHON_TEST_FRAME = False
PYTHON_TEST_FILE  = None

# Browser prefs

# Mozilla prefs
MOZILLA_CREATE_NEW_PROFILE     = True
MOZILLA_REMOVE_PROFILE_ON_EXIT = True

MOZILLA_PROFILE_PATH = tempfile.mkdtemp(suffix='.windmill')

while MOZILLA_PROFILE_PATH.find('-') is not -1:
    shutil.rmtree(MOZILLA_PROFILE_PATH)
    MOZILLA_PROFILE_PATH = tempfile.mkdtemp(suffix='.windmill')

if PLATFORM == 'darwin':
    firefoxApp = os.path.join('Applications', 'Firefox.app')
    firefoxDir = os.path.join(os.path.expanduser('~/'), firefoxApp)

    if not os.path.isdir(firefoxDir):
        firefoxDir = os.path.join('/', firefoxApp)

    MOZILLA_DEFAULT_PROFILE = os.path.join(firefoxDir, 'Contents', 'MacOS', 'defaults', 'profile')
    MOZILLA_BINARY          = os.path.join(firefoxDir, 'Contents', 'MacOS', 'firefox-bin')

elif sys.platform == 'linux2':
    firefoxBin = findInPath('firefox')

    if firefoxBin is not None and os.path.isfile(firefoxBin):
        MOZILLA_BINARY = firefoxBin

    if os.path.isdir('/usr/share/firefox/defaults/profile'):
        MOZILLA_DEFAULT_PROFILE = '/usr/share/firefox/defaults/profile'

elif os.name == 'nt' or sys.platform == 'cygwin':
    IE_BINARY  = findInPath('iexplore')
    firefoxBin = findInPath('firefox')

    if firefoxBin is None:
        try:
            firefoxBin = os.path.join(os.environ['ProgramFiles'], 'Mozilla Firefox', 'firefox.exe')
        except:
            firefoxBin = None

    if firefoxBin is not None and os.path.isfile(firefoxBin):
        firefoxDir = os.path.dirname(firefoxBin)

        MOZILLA_BINARY          = firefoxBin
        MOZILLA_DEFAULT_PROFILE = os.path.join(firefoxDir, 'defaults', 'profile')

if __name__ == '__main__':
    if '--test' in sys.argv:
        print 'running on           ', PLATFORM
        print 'we are at            ', WINDMILL_PATH
        print 'our JS is at         ', JS_PATH
        print 'firefox is at        ', MOZILLA_BINARY
        print 'default profile is at', MOZILLA_DEFAULT_PROFILE

<|endoftext|>


<commit_before>#!/usr/bin/env python
import asyncio
import datetime
import emoji
import os
import sys

from telethon import TelegramClient
from telethon.tl.types import MessageMediaDocument
from telethon.tl.types import MessageMediaPhoto
from telethon.tl.types import MessageMediaWebPage
from config import API_ID, API_HASH, PHONE_NUM, SESSION_ID, CHAT_ID

MEDIA_DIR = "media"
AUDIO_DIR = "audio"
VIDEO_DIR = "video"
IMG_DIR = "image"
WEB_DIR = "web"
MONTHS_DICT = {
    1: "Gener",
    2: "Febrer",
    3: "Març",
    4: "Abril",
    5: "Maig",
    6: "Juny",
    7: "Juliol",
    8: "Agost",
    9: "Setembre",
    10: "Octubre",
    11: "Novembre",
    12: "Desembre"
}

class Message(object):
    def __init__(self, message):
        self.message = message

def create_session(session_id, phone_num, api_id, api_hash):
    """Creates a Telegram session."""
    client = TelegramClient(session_id, api_id, api_hash)
    client.start()
    return client

def format_media_path(msg, name, new_dir, extension):
    """Formats the file containing the media."""
    new_path = "{}-{}-{} {}:{:02d}:{:02d}_{}.{}".format(
        msg.date.year, msg.date.month, msg.date.day,
        msg.date.hour, msg.date.minute, msg.date.second, name,
        extension)
    return os.path.join(new_dir, new_path)

def download_media(msg, name, client, media_dir=MEDIA_DIR, audio_dir=AUDIO_DIR,
                   video_dir=VIDEO_DIR, img_dir=IMG_DIR, web_dir=WEB_DIR):
    """Downloads media, if any."""
    os.makedirs(media_dir, exist_ok=True)
    audio_dir = os.path.join(media_dir, audio_dir)
    os.makedirs(audio_dir, exist_ok=True)
    img_dir = os.path.join(media_dir, img_dir)
    os.makedirs(img_dir, exist_ok=True)
    video_dir = os.path.join(media_dir, video_dir)
    os.makedirs(video_dir, exist_ok=True)

    out_msg = ""

    if isinstance(msg.media, MessageMediaWebPage):
        content = "\\url{{{}}} ".format(msg.media.webpage.url)
        out_msg = get_message_string(msg, name, content)
    elif isinstance(msg.media, MessageMediaPhoto):
        path = format_media_path(msg, name, img_dir, "jpg")
        wait_fun(client.download_media, message=msg,
                 file="{}.jpg".format(path))
        out_msg = "\myfigure{0.3}{%s}{%s}" % (
            path, get_message_string(msg, name, msg.message))
    elif isinstance(msg.media, MessageMediaDocument):
        if msg.media.document.mime_type == "video/mp4":
            path = format_media_path(msg, name, video_dir, "mp4")
            path_thumb = format_media_path(msg, name, video_dir, "jpg")
            wait_fun(client.download_media, message=msg,
                     file="{}".format(path))
            wait_fun(client.download_media, message=msg,
                     thumb=-1, file=path_thumb)
            content = "(video a {})".format(path)
            out_msg = "\myfigure{0.3}{%s}{%s}" % (
                path_thumb, get_message_string(msg, name,
                                               content + msg.message))
        elif msg.media.document.mime_type == "audio/ogg":
            path = format_media_path(msg, name, audio_dir, "ogg")
            wait_fun(client.download_media, message=msg,
                     file="{}".format(path))
            content = "(\`audio a {})".format(path)
            out_msg = get_message_string(msg, name,
                                         content + msg.message)
        else:
            import ipdb; ipdb.set_trace()
            print("CACA DOCUMENT")
            print(msg)
            print(msg.media)
            sys.exit()
    else:
        print(msg)
        print(msg.media)
        sys.exit()

    return out_msg

def get_message_string(msg, name, content):
    """Gets the actual string, customly formatted."""
    if content is None:
        content = ""
    else:
        content = ": " + parse_emojis(content)
    return '[{}:{:02d}h] \\textbf{{{}}}{}'.format(
        msg.date.hour, msg.date.minute, name,
        content.replace("_", "\_"))

def parse_emojis(in_str):
    """Adds the DejaSans prefix for LaTeX parsing."""
    out_str = ""
    for c in in_str:
        if c in emoji.UNICODE_EMOJI:
            out_str += "{\DejaSans " + c + "}"
        else:
            out_str += c
    return out_str

def add_new_day(date):
    return "\\textbf{{{}/{}/{}}}\n\n".format(
        date.day, date.month, date.year)

def add_new_month(date):
    return "\mychapter{%s del %d}\n\n" % \
        (MONTHS_DICT[date.month], date.year)

def get_chat(client, chat_id):
    """Gets the chat with the given id and the open client."""
    chat = None
    for d in client.iter_dialogs():
        if d.entity.id == CHAT_ID:
            chat = d.entity
            break
    return chat

def wait_fun(fun, **args):
    """Run function asynchronously and waits for it to finish."""
    loop = asyncio.get_event_loop()
    loop.run_until_complete(fun(**args))

def get_name(msg, ps_dict):
    """Returns name from the given message."""
    return "{} {}".format(ps_dict[msg.from_id].first_name,
                          ps_dict[msg.from_id].last_name[0])

def get_participants(client, chat):
    """Gets a dictionary of participants in the given chat."""
    participants = {}
    for p in client.iter_participants(chat):
        participants[p.id] = p
    return participants

if __name__ == "__main__":
    # Open client and chat
    client = create_session(SESSION_ID, PHONE_NUM, API_ID, API_HASH)
    chat = get_chat(client, CHAT_ID)

    if chat is None:
        print("Group {} not found!".format(CHAT_ID))
        sys.exit()

    # Get all participants
    ps = get_participants(client, chat)

    # Download Chat Pic
    wait_fun(client.download_profile_photo, entity=chat, file='media/chat_pic.jpg')

    date = datetime.datetime.today()
    date = date.replace(day=4)
    # date = date.replace(year=2010)

    prev_month = None
    prev_day = None

    # Parse each message, from oldest to newest
    for message in client.iter_messages(chat, offset_date=date, reverse=True):
        # Empty string
        out_str = ""

        # Start a chapter for every new month
        if prev_month is None or prev_month != date.month:
            out_str += add_new_month(message.date)
            prev_month = date.month

        # Start a subsection for every new day
        if prev_day is None or prev_day != date.day:
            out_str += add_new_day(message.date)
            prev_day = date.day

        name = get_name(message, ps)
        if message.media:
            out_str += download_media(message, name, client)
        else:
            out_str += get_message_string(message, name, message.message)

        # Write to latex
        print(out_str)
        with open("latex/content.tex", "a") as f:
            f.write(out_str + '\n\n')
<commit_msg>Added more types of messages<commit_after>#!/usr/bin/env python
import asyncio
import datetime
import emoji
import os
import sys

from telethon import TelegramClient
from telethon.tl.types import MessageMediaDocument
from telethon.tl.types import MessageMediaPhoto
from telethon.tl.types import MessageMediaWebPage
from telethon.tl.types import MessageMediaGeo
from telethon.tl.types import WebPageEmpty
from telethon.tl.types import MessageMediaUnsupported
from config import API_ID, API_HASH, PHONE_NUM, SESSION_ID, CHAT_ID

MEDIA_DIR = "media"
AUDIO_DIR = "audio"
VIDEO_DIR = "video"
IMG_DIR = "image"
WEB_DIR = "web"
MONTHS_DICT = {
    1: "Gener",
    2: "Febrer",
    3: "Març",
    4: "Abril",
    5: "Maig",
    6: "Juny",
    7: "Juliol",
    8: "Agost",
    9: "Setembre",
    10: "Octubre",
    11: "Novembre",
    12: "Desembre"
}

class Message(object):
    def __init__(self, message):
        self.message = message

def create_session(session_id, phone_num, api_id, api_hash):
    """Creates a Telegram session."""
    client = TelegramClient(session_id, api_id, api_hash)
    client.start()
    return client

def format_media_path(msg, name, new_dir, extension):
    """Formats the file containing the media."""
    new_path = "{}-{}-{} {}:{:02d}:{:02d}_{}.{}".format(
        msg.date.year, msg.date.month, msg.date.day,
        msg.date.hour, msg.date.minute, msg.date.second, name,
        extension)
    return os.path.join(new_dir, new_path)

def download_media(msg, name, client, media_dir=MEDIA_DIR, audio_dir=AUDIO_DIR,
                   video_dir=VIDEO_DIR, img_dir=IMG_DIR, web_dir=WEB_DIR):
    """Downloads media, if any."""
    os.makedirs(media_dir, exist_ok=True)
    audio_dir = os.path.join(media_dir, audio_dir)
    os.makedirs(audio_dir, exist_ok=True)
    img_dir = os.path.join(media_dir, img_dir)
    os.makedirs(img_dir, exist_ok=True)
    video_dir = os.path.join(media_dir, video_dir)
    os.makedirs(video_dir, exist_ok=True)

    out_msg = ""

    if isinstance(msg.media, MessageMediaWebPage):
        content = msg.message
        if not isinstance(msg.media.webpage, WebPageEmpty):
            content = "\\url{{{}}} ".format(msg.media.webpage.url)
        out_msg = get_message_string(msg, name, content)
    elif isinstance(msg.media, MessageMediaGeo):
        content = "Geolocation({}, {})".format(
            msg.media.geo.long,
            msg.media.geo.lat)
        out_msg = get_message_string(msg, name, content)
    elif isinstance(msg.media, MessageMediaPhoto):
        path = format_media_path(msg, name, img_dir, "jpg")
        wait_fun(client.download_media, message=msg,
                 file="{}.jpg".format(path))
        out_msg = "\myfigure{0.3}{%s}{%s}" % (
            path, get_message_string(msg, name, msg.message))
    elif isinstance(msg.media, MessageMediaDocument):
        if msg.media.document.mime_type == "video/mp4" or \
                msg.media.document.mime_type == "video/3gpp":
            ext = msg.media.document.mime_type.split("/")[1]
            path = format_media_path(msg, name, video_dir, ext)
            wait_fun(client.download_media, message=msg,
                     file="{}".format(path))
            content = "(video a {})".format(path)
            try:
                # Try to download a thumbnail of the video
                path_thumb = format_media_path(msg, name, video_dir, "jpg")
                wait_fun(client.download_media, message=msg,
                        thumb=-1, file=path_thumb)
                out_msg = "\myfigure{0.3}{%s}{%s}" % (
                    path_thumb, get_message_string(msg, name,
                                                content + msg.message))
            except TypeError:
                out_msg = get_message_string(msg, name, msg.message)
        elif msg.media.document.mime_type == "audio/ogg":
            path = format_media_path(msg, name, audio_dir, "ogg")
            wait_fun(client.download_media, message=msg,
                     file="{}".format(path))
            content = "(\`audio a {})".format(path)
            out_msg = get_message_string(msg, name,
                                         content + msg.message)
        else:
            import ipdb; ipdb.set_trace()
            print("CACA DOCUMENT")
            print(msg)
            print(msg.media)
            sys.exit()
    elif isinstance(msg.media, MessageMediaUnsupported):
        out_msg = get_message_string(msg, name, "(Message not parsed) " + msg.message)
    else:
        import ipdb; ipdb.set_trace()
        print(msg)
        print(msg.media)
        sys.exit()

    return out_msg

def get_message_string(msg, name, content):
    """Gets the actual string, customly formatted."""
    if content is None:
        content = ""
    else:
        content = ": " + parse_emojis(content)
    return '[{}:{:02d}h] \\textbf{{{}}}{}'.format(
        msg.date.hour, msg.date.minute, name,
        content.replace("_", "\_"))

def parse_emojis(in_str):
    """Adds the DejaSans prefix for LaTeX parsing."""
    out_str = ""
    for c in in_str:
        if c in emoji.UNICODE_EMOJI:
            out_str += "{\DejaSans " + c + "}"
        else:
            out_str += c
    return out_str

def add_new_day(date):
    return "\\textbf{{{}/{}/{}}}\n\n".format(
        date.day, date.month, date.year)

def add_new_month(date):
    return "\mychapter{%s del %d}\n\n" % \
        (MONTHS_DICT[date.month], date.year)

def get_chat(client, chat_id):
    """Gets the chat with the given id and the open client."""
    chat = None
    for d in client.iter_dialogs():
        if d.entity.id == CHAT_ID:
            chat = d.entity
            break
    return chat

def wait_fun(fun, **args):
    """Run function asynchronously and waits for it to finish."""
    loop = asyncio.get_event_loop()
    loop.run_until_complete(fun(**args))

def get_name(msg, ps_dict):
    """Returns name from the given message."""
    # Remove middle name if any
    try:
        first_name = ps_dict[msg.from_id].first_name.split(" ")[0]
    except KeyError:
        import ipdb; ipdb.set_trace()
        pass

    # Get only initial of last name
    last_initial = ps_dict[msg.from_id].last_name[0]
    return "{} {}".format(first_name, last_initial)

def get_participants(client, chat):
    """Gets a dictionary of participants in the given chat."""
    participants = {}
    for p in client.iter_participants(chat):
        participants[p.id] = p
    print(participants)
    # from telethon.tl.functions.users import GetFullUserRequest
    # caca = wait_fun(client, GetFullUserRequest(2390325))
    # import ipdb; ipdb.set_trace()
    # caca = await client(GetFullUserRequest(2390325))
    return participants

def process():
    """Main process."""
    # Open client and chat
    client = create_session(SESSION_ID, PHONE_NUM, API_ID, API_HASH)
    chat = get_chat(client, CHAT_ID)

    if chat is None:
        print("Group {} not found!".format(CHAT_ID))
        sys.exit()

    # Get all participants
    ps = get_participants(client, chat)

    # Download Chat Pic
    wait_fun(client.download_profile_photo, entity=chat, file='media/chat_pic.jpg')

    date = datetime.datetime.today()
    date = date.replace(day=21)
    date = date.replace(month=9)
    date = date.replace(year=2010)

    prev_month = None
    prev_day = None

    # Parse each message, from oldest to newest
    for message in client.iter_messages(chat, offset_date=date, reverse=True):
        # Empty string
        out_str = ""

        # Start a chapter for every new month
        if prev_month is None or prev_month != date.month:
            out_str += add_new_month(message.date)
            prev_month = date.month

        # Start a subsection for every new day
        if prev_day is None or prev_day != date.day:
            out_str += add_new_day(message.date)
            prev_day = date.day

        name = get_name(message, ps)
        if message.media:
            out_str += download_media(message, name, client)
        else:
            out_str += get_message_string(message, name, message.message)

        # Write to latex
        print(out_str)
        with open("latex/content.tex", "a") as f:
            f.write(out_str + '\n\n')
    print("Done")

if __name__ == "__main__":
    process()
<|endoftext|>


<commit_before># Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy
# of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from oslo_config import cfg

periodic_opts = [
    cfg.BoolOpt('periodic_global_stack_list',
                default=False,
                help="List Heat stacks globally when syncing clusters. "
                     "Default is to do retrieve each cluster's stack  "
                     "individually. Reduces number of requests against "
                     "Heat API if enabled but requires changes to Heat's "
                     "policy.json."),
    cfg.BoolOpt('periodic_enable',
                default=True,
                help='Enable periodic tasks.'),
    cfg.IntOpt('periodic_interval_max',
               default=60,
               help='Max interval size between periodic tasks execution in '
                    'seconds.'),
]

def register_opts(conf):
    conf.register_opts(periodic_opts)

def list_opts():
    return {
        "DEFAULT": periodic_opts
    }
<commit_msg>Remove unused config periodic_global_stack_list<commit_after># Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy
# of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from oslo_config import cfg

periodic_opts = [
    cfg.BoolOpt('periodic_enable',
                default=True,
                help='Enable periodic tasks.'),
    cfg.IntOpt('periodic_interval_max',
               default=60,
               help='Max interval size between periodic tasks execution in '
                    'seconds.'),
]

def register_opts(conf):
    conf.register_opts(periodic_opts)

def list_opts():
    return {
        "DEFAULT": periodic_opts
    }
<|endoftext|>


<commit_before>#
# See https://github.com/dials/dials/wiki/pytest for documentation on how to
# write and run pytest tests, and an overview of the available features.
#

from __future__ import absolute_import, division, print_function

import os

import pytest

try:
    import dials_data as pkg_dials_data

    dials_data = pkg_dials_data.dials_data
except ImportError:
    pkg_dials_data = None

    @pytest.fixture(scope="session")
    def dials_data():
        pytest.skip("Test requires python package dials_data")

def pytest_addoption(parser):
    """Add a '--runslow' option to py.test."""
    if pkg_dials_data:
        pkg_dials_data.pytest_addoption(parser)

    try:
        parser.addoption(
            "--regression",
            action="store_true",
            default=False,
            help="run regression tests",
        )
    except ValueError:
        pass  # Thrown in case the command line option is already defined
    parser.addoption(
        "--runslow", action="store_true", default=False, help="run slow tests"
    )

def pytest_collection_modifyitems(config, items):
    """Tests marked as slow will not be run unless slow tests are enabled with
    the '--runslow' parameter or the test is selected specifically. The
    latter allows running slow tests via the libtbx compatibility layer."""
    if not config.getoption("--runslow") and len(items) > 1:
        skip_slow = pytest.mark.skip(reason="need --runslow option to run")
        for item in items:
            if "slow" in item.keywords:
                item.add_marker(skip_slow)

@pytest.fixture(scope="session")
def dials_regression():
    """Return the absolute path to the dials_regression module as a string.
    Skip the test if dials_regression is not installed."""
    try:
        import dials_regression as dr
    except ImportError:
        pytest.skip("dials_regression required for this test")
    return os.path.dirname(dr.__file__)

@pytest.fixture
def run_in_tmpdir(tmpdir):
    """Shortcut to create a temporary directory and then run the test inside
    this directory."""
    tmpdir.chdir()
    return tmpdir
<commit_msg>Don't define --regression command line option<commit_after>#
# See https://github.com/dials/dials/wiki/pytest for documentation on how to
# write and run pytest tests, and an overview of the available features.
#

from __future__ import absolute_import, division, print_function

import os

import pytest

try:
    import dials_data as pkg_dials_data

    dials_data = pkg_dials_data.dials_data
except ImportError:
    pkg_dials_data = None

    @pytest.fixture(scope="session")
    def dials_data():
        pytest.skip("Test requires python package dials_data")

def pytest_addoption(parser):
    """Add a '--runslow' option to py.test."""
    if pkg_dials_data:
        pkg_dials_data.pytest_addoption(parser)

    parser.addoption(
        "--runslow", action="store_true", default=False, help="run slow tests"
    )

def pytest_collection_modifyitems(config, items):
    """Tests marked as slow will not be run unless slow tests are enabled with
    the '--runslow' parameter or the test is selected specifically. The
    latter allows running slow tests via the libtbx compatibility layer."""
    if not config.getoption("--runslow") and len(items) > 1:
        skip_slow = pytest.mark.skip(reason="need --runslow option to run")
        for item in items:
            if "slow" in item.keywords:
                item.add_marker(skip_slow)

@pytest.fixture(scope="session")
def dials_regression():
    """Return the absolute path to the dials_regression module as a string.
    Skip the test if dials_regression is not installed."""
    try:
        import dials_regression as dr
    except ImportError:
        pytest.skip("dials_regression required for this test")
    return os.path.dirname(dr.__file__)

@pytest.fixture
def run_in_tmpdir(tmpdir):
    """Shortcut to create a temporary directory and then run the test inside
    this directory."""
    tmpdir.chdir()
    return tmpdir
<|endoftext|>