def get_event_by_id(event_id):
    event = Event.objects.get(id=event_id)
    return event def get_filtered_events(
        search_filter=None,
        country_filter=None,
        theme_filter=None,
        audience_filter=None,
        past_events=None):
    """
    Filter events by given filter
    """
    filter_args = ()

    # default
    filter_kwargs = {'status': 'APPROVED'}

    if not past_events:
        filter_kwargs['end_date__gte'] = datetime.datetime.now()

    if search_filter:
        filter_args = (
            Q(
                title__icontains=search_filter) | Q(
                description__icontains=search_filter) | Q(
                tags__name__icontains=search_filter) | Q(
                    organizer__icontains=search_filter) | Q(
                        location__icontains=search_filter),)

    if country_filter and country_filter not in [custom_country[
            0] for custom_country in Event.CUSTOM_COUNTRY_ENTRIES]:
        filter_kwargs['country'] = country_filter

    if theme_filter:
        filter_kwargs['theme__in'] = theme_filter

    if audience_filter:
        audience = EventAudience.objects.filter()
        filter_kwargs['audience__in'] = audience_filter

    if len(filter_args) > 0:
        events = Event.objects.filter(*filter_args, **filter_kwargs).distinct()
    else:
        events = Event.objects.filter(**filter_kwargs).distinct()

    return events def get_approved_events(limit=None, order=None, country_code=None, past=False):
    """
    Select all events which are approved and optionally limit and/or order them
    """

    events = Event.objects.filter(status='APPROVED')

    if not past:
        events = events.filter(end_date__gte=datetime.datetime.now())
    if country_code:
        events = events.filter(country=country_code)
    if order:
        events = events.order_by(order)
    if limit:
        events = events[:limit]

    return events def get_pending_events(limit=None, order=None, country_code=None, past=False):
    """
    Select all future or past events which are pending and optionally limit and/or order them
    """

    events = Event.objects.filter(status='PENDING')
    if not past:
        events = events.filter(end_date__gte=datetime.datetime.now())
    if country_code:
        events = events.filter(country=country_code)
    if order:
        events = events.order_by(order)
    if limit:
        events = events[:limit]
    return events def get_created_events(
        creator,
        limit=None,
        order=None,
        country_code=None,
        past=False):
    """
    Select all future or past events which are created by user and optionally limit and/or order them
    """

    events = Event.objects.filter(creator=creator)
    if not past:
        events = events.filter(end_date__gte=datetime.datetime.now())
    if country_code:
        events = events.filter(country=country_code)
    if order:
        events = events.order_by(order)
    if limit:
        events = events = events[:limit]
    return events def events_pending_for_report_for(creator):
    return events_pending_for_report().filter(creator=creator) def reporeted_events_for(creator):
    return reported_events().filter(creator=creator) def get_next_or_previous(event, country_code=None, past=False, direction=True):
    """
    Get next or previous pending event
    """

    next_event = None
    events = Event.objects.filter(status='PENDING')

    if direction:
        events = events.filter(pk__gt=event.pk).order_by("pk")
    else:
        events = events.filter(pk__lt=event.pk).order_by("-pk")

    if not past:
        events = events.filter(end_date__gte=datetime.datetime.now())
    if country_code:
        events = events.filter(country=country_code)

    if events:
        next_event = events[0]

    return next_event def get_nearby_events(event, limit=None, past=False):
    """
    Select ten events which are near by the current event
    """

    events = Event.objects.filter(
        status='APPROVED').filter(
        country=event.country).exclude(
            pk=event.pk)

    if not past:
        events = events.filter(end_date__gte=datetime.datetime.now())
    if limit:
        events = events[:limit]

    return events class AddEventForm(forms.ModelForm):

    email_errors = {
        'required': u'Please enter a valid email, so we can contact you in case of questions.',
        'invalid': u'Can you please check if this is a valid email address?',
    }
    user_email = forms.EmailField(
        required=True,
        label='Your contact email',
        widget=forms.EmailInput(
            attrs={
                "class": "form-control"}),
        error_messages=email_errors,
    )

    class Meta:
        model = Event
        fields = ['title',
                  'organizer',
                  'description',
                  'geoposition',
                  'location',
                  'country',
                  'start_date',
                  'end_date',
                  'event_url',
                  'contact_person',
                  'audience',
                  'theme',
                  'picture',
                  'tags',
                  'user_email',
                  ]

        widgets = {
            'title': forms.TextInput(attrs={"class": "form-control",
                                            "placeholder": "How do you call this event?"}),
            'organizer': forms.TextInput(attrs={"class": "form-control",
                                                "placeholder": "Who is organizing this event?"}),
            'description': forms.Textarea(attrs={"class": "form-control",
                                                 "placeholder": "Tell us a bit about your event."}),
            'location': forms.TextInput(attrs={"id": "autocomplete", "class": "form-control",
                                               "placeholder": "Where will the event be taking place?", }),
            'start_date': forms.TextInput(attrs={"id": "id_datepicker_start", "class": "form-control",
                                                 "autocomplete": "off",
                                                 "placeholder": "When does it start?"}),
            'end_date': forms.TextInput(attrs={"id": "id_datepicker_end", "class": "form-control",
                                               "autocomplete": "off", "placeholder": "When does it end?"}),
            'event_url': forms.TextInput(attrs={"class": "form-control",
                                                "placeholder": "Do you have a website with more information?"}),
            'contact_person': forms.TextInput(attrs={"class": "form-control",
                                                     "placeholder": "Would you like to display a contact email?"}),
            'audience': forms.CheckboxSelectMultiple(),
            'theme': forms.CheckboxSelectMultiple(),
            'tags': forms.TextInput(attrs={"class": "form-control",
                                           "placeholder": "example: Python, Django, Slovenia"}),
        }

        labels = {
            'title': 'Event title',
            'organizer': 'Organizer(s)',
            'description': 'Description',
            'location': 'Location',
            'country': 'Country',
            'start_date': 'Start date',
            'end_date': 'End date',
            'event_url': 'Website',
            'contact_person': 'Contact',
            'picture': 'Image',
            'audience': 'Audience',
            'theme': 'Theme',
            'tags': 'Tags',
        }

        help_texts = {
            'start_date': "Example: YYYY/MM/DD h:m",
            'end_date': "Example: YYYY/MM/DD h:m",
            'audience': "Who is the event for?",
            'theme': "Which aspect of coding will your event cover?",
            'picture': 'Larger images will be resized to 256 x 512 pixels. Maximum upload size is 256 x 1024.',
        }

        error_messages = {
            'title': {
                'required': u'Please enter a title for your event.',
                'invalid': u'Can you please check if this is a valid title?',
            },
            'organizer': {
                'required': u'Please enter an organizer.',
                'invalid': u'Can you please check if this is a valid organizer?',
            },
            'description': {
                'required': u'Please write a short description of what the event is about.',
                'invalid': u'Please check if the description only contains regular text.',
            },
            'geoposition': {
                'invalid': u'Please enter valid coordinates.'
            },
            'location': {
                'required': u'Please enter a location.',
                'invalid': u'Please check your event\'s location',
            },
            'country': {
                'required': u'The event\'s location should be in Europe.',
                'invalid': u'Make sure the event country is written in English.',
            },
            'start_date': {
                'required': u'Please enter a valid date and time (example: 2014-10-22 18:00).',
                'invalid': u'This doesn\'t seem like a valid date and time. Can you check, please?',
            },
            'end_date': {
                'required': u'Please enter a valid date and time (example: 2014-10-22 20:00).',
                'invalid': u'This doesn\'t seem like a valid date and time. Can you check, please?',
            },
            'event_url': {
                'invalid': u'Please enter a valid web address starting with http://',
            },
            'contact_person': {
                'invalid': u'Please enter a valid email address.',
            },
            'picture': {
                'invalid': u'Make sure this is a valid image.',
            },
            'audience': {
                'required': u'If unsure, choose Other and provide more information in the description.',
                'invalid': u'Choose one or more of the provided choices.',
            },
            'theme': {
                'required': u'If unsure, choose Other and provide more information in the description.',
                'invalid': u'Choose one or more of the provided choices.',
            },
            'tags': {
                'required': u'Please type in some tags to categorize the event',
                'invalid': u'Please enter tags in plain text, separated by commas.',
            },
        }

    def clean(self):
        cleaned_data = super(AddEventForm, self).clean()
        start_date = cleaned_data.get('start_date')
        end_date = cleaned_data.get('end_date')

        if start_date and end_date and end_date < start_date:
            msg = u'End date should be greater than start date.'
            self._errors['end_date'] = self.error_class([msg])

        return cleaned_data

    def __init__(self, *args, **kwargs):
        super(AddEventForm, self).__init__(*args, **kwargs) class ReportEventForm(forms.ModelForm):
    error_css_class = 'has-error'
    required_css_class = 'required'

    class Meta:
        model = Event
        fields = ['participants_count',
                  'average_participant_age',
                  'percentage_of_females',
                  'codeweek_for_all_participation_code',
                  'name_for_certificate',
                  ]

        help_texts = {
            'codeweek_for_all_participation_code': "Optional. You can put here your Codeweek4All challenge code, if you got one. If you're not participating, just ignore this field.",
            'percentage_of_females': "Required. Please provide a rough estimate, even if you don't have exact data. A number from 0 to 100.",
            'average_participant_age': "Required. Please provide a rough estimate, even if you don't have exact data. A number greater than 0.",
            'participants_count': "Required. Please provide a rough estimate, even if you don't have exact data. A number greater than 0.",
            'name_for_certificate': "Required. Change this to the name of the event organizer who will be issued a certificate of participation in Code Week. Please use only ASCII (Latin) letters. Letters with accents, umlauts and the like are not supported.",
        }

    def __init__(self, *args, **kwargs):
        super(ReportEventForm, self).__init__(*args, **kwargs)

        # Mark all fields as required by default
        for field_name in self.fields:
            self.fields[field_name].required = True

        # Optional fields
        self.fields['codeweek_for_all_participation_code'].required = False class SearchEventForm(forms.Form):

    countries._countries.append(Event.CUSTOM_COUNTRY_ENTRIES[0])
    countries._countries.append(Event.CUSTOM_COUNTRY_ENTRIES[1])

    # XK is temp code for Kosovo; remove from COUNTRIES_OVERRIDE when
    # Kosovo gets its own ISO code and is added to django-countries
    if not 'Kosovo' in list(dict(countries._countries).values()):
        countries._countries.append((u'XK', u'Kosovo'))

    q = forms.CharField(
        required=False,
        widget=forms.TextInput(
            attrs={
                'placeholder': 'Search for event name or tag',
                'class': 'form-control'}))
    past = forms.ChoiceField(
        label='Include past events',
        required=False,
        choices=(('yes', 'yes'), ('no', 'no')),
        widget=forms.RadioSelect(attrs={'class': 'search-form-element'}),
    )
    country = forms.ChoiceField(
        label='Select country',
        required=False,
        widget=forms.Select(attrs={'class': 'search-form-element'}),
        choices=countries
    )
    theme = forms.ModelMultipleChoiceField(
        queryset=EventTheme.objects.all(),
        label='Theme',
        required=False,
        widget=forms.CheckboxSelectMultiple(
            attrs={
                'class': 'search-form-element'}),
    )
    audience = forms.ModelMultipleChoiceField(
        queryset=EventAudience.objects.all(),
        label='Audience',
        required=False,
        widget=forms.CheckboxSelectMultiple(
            attrs={
                'class': 'search-form-element'}),
    )

    def __init__(self, *args, **kwargs):
        country_code = kwargs.pop('country_code', None)
        past_events = kwargs.pop('past_events')
        search_query = kwargs.pop('search', None)
        theme = kwargs.pop('theme', None)
        audience = kwargs.pop('audience', None)
        super(SearchEventForm, self).__init__(*args, **kwargs)
        if country_code:
            self.fields['country'].initial = country_code
        self.fields['past'].initial = past_events
        if search_query:
            self.fields['q'].initial = search_query
        if theme:
            self.fields['theme'].initial = theme
        if audience:
            self.fields['audience'].initial = audience def get_initial_data(event):
    """
    Processing event to fill in form data
    """
    initial = event.__dict__
    initial['tags'] = event.get_tags()
    initial['audience'] = event.get_audience_array()
    initial['theme'] = event.get_theme_array()
    return initial def change_event_status(event_id):
    event = Event.objects.get(pk=event_id)

    if event.status == 'APPROVED':
        event.status = 'PENDING'

    else:
        event.status = 'APPROVED'

    event.save()
    return event def reject_event_status(event_id):
    event = Event.objects.get(pk=event_id)

    if event.status == 'REJECTED':
        event.status = 'PENDING'

    else:
        event.status = 'REJECTED'

    event.save()
    return event def create_or_update_event(event_id=None, **event_data):
    """
    Creates or updates Event object
    """
    event = Event.objects.filter(id=event_id)
    if event:
        event = event[0]

        if event_data:
            # many to many fields have to updated after other fields are
            # updated
            new_audiences = event_data['audience']
            event_data.pop('audience')
            new_themes = event_data['theme']
            event_data.pop('theme')

            event_tags = []
            if 'tags' in event_data:
                event_tags = event_data['tags']
                event_data.pop('tags')

            # in case we have geoposition data in event_data
            if 'geoposition' in event_data and event_data['geoposition'] != '':
                # updating geoposition field is a bit fuzzy
                event_latitude = event_data['geoposition'][0]
                event_longitude = event_data['geoposition'][1]
                event_data.pop('geoposition')
                # updating all other fields
                event.__dict__.update(event_data)
                # setting new values for geoposition
                event.__dict__['geoposition'].latitude = event_latitude
                event.__dict__['geoposition'].longitude = event_longitude
                event.save()
            else:
                event.__dict__.update(event_data)
                event.save()

            if 'picture' not in event_data:
                event.picture = ''
                event.save()

            # delete old categories and tags and store new ones
            event.audience.clear()
            event.audience.add(*new_audiences)
            event.theme.clear()
            event.theme.add(*new_themes)
            event.tags.set(*event_tags)

    else:
        event = Event.objects.create(**event_data)
        send_email_to_country_ambassadors(event)

    return event def update_user_email(user_id, new_email):
    user = User.objects.get(id=user_id)
    user.email = new_email
    user.save(update_fields=["email"])
    return user def get_ambassadors(country_code=None):
    ambassadors = User.objects \
        .filter(groups__name='ambassadors') \
        .prefetch_related('userprofile') \
        .order_by('date_joined')

    if country_code != None:
        ambassadors = ambassadors.filter(userprofile__country=country_code)

    ambassador_profiles = list({ambassador.profile for ambassador in ambassadors})

    return ambassador_profiles def get_client_ip(forwarded=None, remote=None):
    if settings.DEBUG and remote == '127.0.0.1':
        return '93.103.53.11'
    if forwarded:
        return forwarded.split(',')[0]
    return remote def get_lat_lon_from_user_ip(ip):
    """
    Return latitude and longitude of IP
    """
    g = GeoIP()
    return g.lat_lon(ip) def list_countries():
    all_countries = []
    for code, name in list(countries):
        readable_name = unicode(name)
        all_countries.append((readable_name, code))
    all_countries.sort()
    return all_countries def list_active_countries(with_past_events=False):
    """ List countries with at least an Event associated """
    start_year = 2014 if with_past_events else datetime.datetime.now().year
    events_countries = Event.objects.filter(
            start_date__gte=datetime.date(start_year, 1, 1),
            status='APPROVED'
        ).values_list('country').order_by().distinct()

    active_countries = [(unicode(name), code) for code, name in list(countries) if (code,) in events_countries]

    return active_countries def get_country(country_code, user_ip):

    if country_code and 'media' not in country_code:
        country_name = unicode(dict(countries).get(country_code, 'EU'))
        country = {'country_name': country_name, 'country_code': country_code}
    else:
        country = get_country_from_user_ip(user_ip)
    return country def get_country_from_user_ip(ip):
    """
    Return country of IP
    """
    g = GeoIP()
    return g.country(ip) def \
        count_approved_events_for_country(past=True):
    """
    Count the number of approved events and score for each country
    """

    all_events = Event.objects.filter(status='APPROVED')

    country_count = []

    # not including the first two fake countries in the list
    for country in list(countries)[2:]:
        country_code = country[0]
        country_name = country[1]
        number_of_events = all_events.filter(
            country=country_code).filter(
            start_date__gte=datetime.date(
                datetime.datetime.now().year, 1, 1)).count()
        population = Country.objects.get(iso=country_code).population
        country_score = 0
        if number_of_events > 0 and population > 0 and population != "":
            country_score = 1. * number_of_events / population
        country_entry = {'country_code': country_code,
                         'country_name': country_name,
                         'events': number_of_events,
                         'score': country_score}
        if number_of_events > 0:
            country_count.append(country_entry)

    sorted_count = sorted(
        country_count,
        key=lambda k: k['score'],
        reverse=True)
    return sorted_count def process_image(image_file):
    """
    resize an uploaded image and convert to png format
    """
    size = 256, 512
    image_name = image_file.name
    image_basename, image_format = os.path.splitext(image_name)
    new_image_name = "%s_%s.png" % (slugify(image_basename), uuid.uuid4())

    try:
        im = PilImage.open(image_file)
        if max(im.size) > max(size):
            im.thumbnail(size, PilImage.ANTIALIAS)

        thumb_io = StringIO.StringIO()
        im.save(thumb_io, format='png')
        return InMemoryUploadedFile(
            thumb_io,
            None,
            new_image_name,
            'image/png',
            thumb_io.len,
            None)

    except IOError as e:
        msg = 'Failed while processing image (image_file=%s, image_name=%s, error_number=%s, error=%s).' \
              % (image_file, new_image_name, e.errno, e.strerror, )
        raise UploadImageError(msg) class ImageSizeTooLargeException(Exception):
    pass class UploadImageError(Exception):
    pass def generate_certificate_for(event_id, certificate_name, name_of_certificate_holder):
    resources_path             = dirname(realpath(__file__)) + '/resources/'
    static_files_path          = dirname(dirname(realpath(__file__))) + '/staticfiles/certificates/'

    generic_template_path      = resources_path + 'template.tex'
    personalized_template_path = resources_path + str(event_id) + '.tex'
    resulting_certificate_path = static_files_path + certificate_name

    with open(generic_template_path) as template:
        personalized_certificate_content = template.read().replace(
            '<CERTIFICATE_HOLDER_NAME>', tex_escape(name_of_certificate_holder))

    with open(personalized_template_path, 'w') as personalized_template:
        personalized_template.write(personalized_certificate_content.encode('utf-8'))

    commands = [
        'cd ' + resources_path,
        'pdflatex -interaction=nonstopmode -output-directory ' + resources_path + ' ' + personalized_template_path,
        'mkdir -p ' + static_files_path,
        'mv -f ' + personalized_template_path.replace('.tex', '.pdf') + ' ' + resulting_certificate_path,
        'rm -rf ' + resources_path + str(event_id) + '.*',
    ]

    if system(' && '.join(commands)) != 0:
        return False

    return resulting_certificate_path
from datetime import datetime
from collections import OrderedDict
from django.contrib.gis.geoip import GeoIPException
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.template import loader
from django.template import Context
from django.http import HttpResponseRedirect
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.core import serializers
from django.core.urlresolvers import reverse
from django.core.exceptions import ObjectDoesNotExist
from django_countries import countries
from django.views.decorators.cache import never_cache
from django.http import Http404
from django.shortcuts import redirect
from api.processors import get_event_by_id
from api.processors import get_filtered_events
from api.processors import get_approved_events
from api.processors import get_pending_events
from api.processors import get_created_events
from api.processors import events_pending_for_report_for
from api.processors import reporeted_events_for
from api.processors import get_next_or_previous
from api.processors import get_nearby_events
from web.forms.event_form import AddEventForm
from web.forms.event_form import ReportEventForm
from web.forms.event_form import SearchEventForm
from web.processors.event import get_initial_data
from web.processors.event import change_event_status
from web.processors.event import reject_event_status
from web.processors.event import create_or_update_event
from web.processors.user import update_user_email
from web.processors.user import get_ambassadors
from web.processors.event import get_client_ip
from web.processors.event import get_lat_lon_from_user_ip
from web.processors.event import list_countries, list_active_countries
from web.processors.event import get_country
from web.processors.event import get_country_from_user_ip
from web.processors.event import count_approved_events_for_country
from web.processors.media import process_image
from web.processors.media import ImageSizeTooLargeException
from web.processors.media import UploadImageError
from web.decorators.events import can_edit_event
from web.decorators.events import can_moderate_event
from web.decorators.events import is_ambassador
from certificates.generator import generate_certificate_for
                    event_data['picture'] = process_image(picture)

                event_data.update(event_form.cleaned_data)
                event_data['creator'] = request.user

                # checking if user entered a different email than in her
                # profile
                if request.user.email != event_data['user_email']:
                    update_user_email(
                        request.user.id, event_data['user_email'])
                event_data.pop('user_email')

                event = create_or_update_event(**event_data)

                t = loader.get_template('alerts/thank_you.html')
                c = Context({'event': event, })
                messages.info(request, t.render(c))

                return HttpResponseRedirect(
                    reverse(
                        'web.view_event',
                        args=[
                            event.pk,
                            event.slug]))

            except ImageSizeTooLargeException:
                messages.error(
                    request, 'The image is just a bit too big for us. '
                    'Please reduce your image size and try agin.')
            except UploadImageError as e:
                messages.error(request, e.message)
    else:
        event_form = AddEventForm(initial={
            'user_email': request.user.email,
            'contact_person': request.user.email,
        })

    return render_to_response("pages/add_event.html", {
        'form': event_form,
    }, context_instance=RequestContext(request))


@login_required
@can_edit_event
@never_cache
def edit_event(request, event_id):
    event = get_event_by_id(event_id)
    user = request.user
    initial = get_initial_data(event)
    initial['user_email'] = request.user.email

    event_data = {}

    if request.method == 'POST':
        event_form = AddEventForm(data=request.POST, files=request.FILES)
    else:
        event_form = AddEventForm(initial=initial)

    existing_picture = event.picture

    if event_form.is_valid():
        # picture_check works with jasny bootstrap magix
        picture_check = request.POST.get('picture')
        picture = request.FILES.get('picture', None)
        event_data = event_form.cleaned_data
        event_data['creator'] = request.user

        # checking if user entered a different email than in her profile
        if user.email != event_data['user_email']:
            update_user_email(user.id, event_data['user_email'])
        event_data.pop('user_email')

        try:
            if picture:
                if picture.size > (256 * 1024):
                    raise ImageSizeTooLargeException('Image size too large.')
                event_data['picture'] = process_image(picture)
            elif picture_check == "nochange":
                event_data['picture'] = existing_picture
            else:
                del event_data['picture']

            create_or_update_event(event_id, **event_data)

            return HttpResponseRedirect(
                reverse(
                    'web.view_event',
                    kwargs={
                        'event_id': event.id,
                        'slug': event.slug}))

        except ImageSizeTooLargeException:
            messages.error(
                request, 'The image is just a bit too big for us (must be up to 256 kb). '
                'Please reduce your image size and try agin.')
        except UploadImageError as e:
            messages.error(request, e.message)

    return render_to_response(
        'pages/add_event.html', {
            'form': event_form,
            'address': event_data.get('location', None),
            'editing': True,
            'picture_url': event.picture,
        }, context_instance=RequestContext(request))


@login_required
@can_edit_event
@never_cache
def report_event(request, event_id):
    event = get_event_by_id(event_id)
    user = request.user
    initial = get_initial_data(event)
    initial['name_for_certificate'] = event.organizer
    event_report_fields = OrderedDict()

    if request.method == 'POST':
        report_event_form = ReportEventForm(data=request.POST)
    else:

        report_event_form = ReportEventForm(initial=initial)