示例#1
0
 def check_mode_testing(self):
     # ask if user is sure about running server in TEST mode?
     self.log('Checking MODE ...')
     MODE = Config('MODE.SELECTED').value
     if MODE != 'PRODUCTION':
         Log().show_message(
             'MODE in _setup/config.json is set to TESTING - this makes your server easy to attack, if you use that option on a deployed server that is accessible via the internet. Do you want to continue? (Enter Y to continue)'
         )
         are_you_sure = input()
         if are_you_sure.lower() != 'y':
             Log().show_message(
                 'Ok, stopped server. You can change the mode in your _setup/config.json file.'
             )
             exit()
示例#2
0
    def RESULT__extractSpace(self, json_meetup_result):
        Log().print('RESULT__extractSpace(json_meetup_result)')
        from _database.models import Space
        from _setup.models import Config

        if 'how_to_find_us' in json_meetup_result:
            spaces = Space.objects.all()

            for space in spaces.iterator():
                if space.str_name_en_US.lower(
                ) in json_meetup_result['how_to_find_us'].lower():
                    return space

        # else...
        EVENTS_SPACES_OVERWRITE = Config(
            'EVENTS.EVENTS_SPACES_OVERWRITE').value
        for field in EVENTS_SPACES_OVERWRITE:
            if field in json_meetup_result['name']:
                return Space.objects.QUERYSET__by_name(
                    EVENTS_SPACES_OVERWRITE[field])
        else:
            return Space.objects.QUERYSET__by_name(
                Config('EVENTS.EVENTS_SPACE_DEFAULT').value)
示例#3
0
class View(View):
    logs = ['self.__init__']
    started = round(time.time())
    show_log = True
    space_name = Config('BASICS.NAME').value
    admin_url = Secret('DJANGO.ADMIN_URL').value
    path = ''

    def log(self, text):
        import os
        self.logs.append(text)
        if self.show_log == True:
            Log().print('{}'.format(text), os.path.basename(__file__),
                        self.started)
示例#4
0
    def RESULT__extractGuilde(self, json_meetup_result):
        Log().print('RESULT__extractGuilde(json_meetup_result)')
        from _database.models import Guilde
        from _setup.models import Config

        EVENTS_GUILDES_OVERWRITE = Config(
            'EVENTS.EVENTS_GUILDES_OVERWRITE').value

        for str_keyword in EVENTS_GUILDES_OVERWRITE:
            if str_keyword in json_meetup_result['name']:
                Log().print('--> {} found in result.name'.format(str_keyword))
                Log().print('--> return guilde')
                return Guilde.objects.filter(str_name_en_US=EVENTS_GUILDES_OVERWRITE[str_keyword]).first()
        else:
            Log().print('--> return None')
            return None
示例#5
0
    def DATETIME__from_date_and_time_STR(self, str__date, str__time):
        import pytz
        from datetime import datetime
        from _setup.models import Config

        TIMEZONE_STRING = Config('PHYSICAL_SPACE.TIMEZONE_STRING').value
        if 'AM' in str__time or 'PM' in str__time:
            datetime_input = pytz.timezone(TIMEZONE_STRING).localize(
                datetime.strptime(
                    str(str__date + ' ' + str__time.replace(' ', '')),
                    "%Y-%m-%d %I:%M%p"))
        else:
            datetime_input = pytz.timezone(TIMEZONE_STRING).localize(
                datetime.strptime(
                    str(str__date + ' ' + str__time.replace(' ', '')),
                    "%Y-%m-%d %H:%M"))
        Log().print('--> return DATETIME')
        return datetime_input
示例#6
0
    def __init__(self, request=None):
        from _database.models import Event
        from _apis.models import Notify
        from _setup.models import Config
        from django.http import JsonResponse

        if not request.GET.get('str_slug', None) or Event.objects.filter(
                str_slug=request.GET.get('str_slug', None)).exists() == False:
            response = JsonResponse({
                'success': False,
                'error': '--> Failed: Result not found'
            })
            response.status_code = 404
        else:

            # approve event and all upcoming ones
            event = Event.objects.filter(
                str_slug=request.GET.get('str_slug', None)).first()

            if event.boolean_approved and (
                    not request or request.user.is_authenticated == False):
                response = JsonResponse({
                    'success':
                    False,
                    'error':
                    '--> Failed: User not logged in'
                })
                response.status_code = 403

            else:
                print('--> Delete all upcoming events')
                event.delete_series()

                # notify via slack that event was deleted and by who
                if 'HTTP_HOST' in request.META and request.META[
                        'HTTP_HOST'] == Config('WEBSITE.DOMAIN').value:
                    Notify().send('🚫' + str(request.user) +
                                  ' deleted the event "' +
                                  event.str_name_en_US + '"')

                response = JsonResponse({'success': True})
                response.status_code = 200

        self.value = response
示例#7
0
    def create_discourse_event(self):
        Log().print('event.create_discourse_event()')
        from _apis.models import create_post
        from django.template.loader import get_template

        if self.str_series_repeat_how_often:
            name = (self.repeating + ' | ' + self.time_range_text + ' | ' +
                    self.str_name_en_US)
        else:
            name = self.datetime_range_text + ' | ' + self.str_name_en_US

        self.url_discourse_event = create_post(
            name,
            get_template('components/discourse/event_post.html').render(
                {'result': self}),
            Config('EVENTS.DISCOURSE_EVENTS_CATEGORY').value)
        super(Event, self).save()
        Log().print('--> return event')
        return self
示例#8
0
    def import_all_from_wiki(self,
                             WIKI_API_URL=Config('BASICS.WIKI.API_URL').value,
                             test=False):
        import requests

        if not WIKI_API_URL:
            Log().print(
                '--> BASICS.WIKI.API_URL not found in config.json -> BASICS - Please add your WIKI_API_URL first.'
            )
            return

        response_json = requests.get(
            WIKI_API_URL +
            '?action=query&list=categorymembers&cmtitle=Category:Meeting_Notes&cmlimit=500&format=json'
        ).json()

        all_wiki_pages = [
            x['title'] for x in response_json['query']['categorymembers']
            if 'Meeting Notes 20' in x['title']
        ]

        if test:
            all_wiki_pages = all_wiki_pages[:4]
        else:
            while 'continue' in response_json and 'cmcontinue' in response_json[
                    'continue']:
                response_json = requests.get(
                    WIKI_API_URL +
                    '?action=query&list=categorymembers&cmcontinue=' +
                    response_json['continue']['cmcontinue'] +
                    '&cmtitle=Category:Meeting_Notes&cmlimit=500&format=json'
                ).json()

                all_wiki_pages += [
                    x['title']
                    for x in response_json['query']['categorymembers']
                    if 'Meeting Notes 20' in x['title']
                ]

        for meeting in all_wiki_pages:
            MeetingNote().import_from_wiki(meeting, WIKI_API_URL)

        print('Imported all meeting notes from wiki')
示例#9
0
    def new(self, original_request):
        self.log('-> EventsView().new()')
        from _database.models import Event, Photo, Space, Guilde
        from _setup.models import Config
        from django.middleware.csrf import get_token
        request = Request(original_request)
        EVENTS_SPACE_DEFAULT = Config('EVENTS.EVENTS_SPACE_DEFAULT').value

        self.context = {
            'view':
            'event_new_view',
            'in_space':
            request.in_space,
            'hash':
            request.hash,
            'ADMIN_URL':
            self.admin_url,
            'user':
            request.user,
            'language':
            request.language,
            'auto_search':
            request.search,
            'slug':
            '/event/new',
            'page_git_url':
            '/tree/master/_database/templates/event_new_view.html',
            'page_name':
            self.space_name + ' | New event',
            'page_description':
            'Organize an event at ' + self.space_name,
            'upcoming_events':
            Event.objects.QUERYSET__upcoming()[:4],
            'default_space':
            Space.objects.filter(str_name_en_US=EVENTS_SPACE_DEFAULT).first(),
            'all_spaces':
            Space.objects.exclude(str_name_en_US=EVENTS_SPACE_DEFAULT),
            'all_guildes':
            Guilde.objects.all(),
            'csrf_token':
            get_token(original_request)
        }
示例#10
0
    def __init__(self, request=None):
        from django.http import JsonResponse
        import json
        import bleach
        from googletrans import Translator
        import emoji
        from _setup.models import Config
        translator = Translator()

        with open('_translations/languages.json') as json_file:
            language_codes = json.load(json_file)

        if request.GET.get('q', None) and request.GET.get('language', None):
            text = emoji.get_emoji_regexp().sub(u'', request.GET.get('q', None))

            response = JsonResponse({'text': translator.translate(
                text=text,
                dest=request.GET.get('language', None)).text
            })

        elif request.GET.get('q', None):
            LANGUAGES = Config('WEBSITE.LANGUAGES').value
            languages = {}

            text = emoji.get_emoji_regexp().sub(u'', request.GET.get('q', None))

            for language in LANGUAGES:
                if len(LANGUAGES) > 1:
                    languages[language] = translator.translate(
                        text=text,
                        dest=language_codes[language]).text
                else:
                    languages[language] = request.GET.get('q', None)

            response = JsonResponse(languages)

        else:
            response = JsonResponse({'error': 'fields missing'})
            response.status_code = 404

        self.value = response
示例#11
0
    def get_lat_lon_and_location(self, str_location):
        from geopy.geocoders import Nominatim
        from geopy.exc import GeocoderTimedOut
        from _setup.models import Config

        geolocator = Nominatim(user_agent=Config('BASICS.NAME').value.lower())
        str_location = str_location.replace('\n', ', ')
        float_lat = None
        float_lon = None
        while float_lat == None and len(str_location) > 0:
            try:
                location = geolocator.geocode(str_location)

                float_lat, float_lon = location.latitude, location.longitude
            except GeocoderTimedOut:
                print('GeocoderTimedOut! This might be solved by turning off your VPN.')
                break
            except:
                str_location = ','.join(str_location.split(',')[:-1])

        return str_location, float_lat, float_lon
示例#12
0
 def __init__(self,
              group=Config('EVENTS.MEETUP_GROUP').value,
              email=Secret('MEETUP.EMAIL').value,
              password=Secret('MEETUP.PASSWORD').value,
              client_id=Secret('MEETUP.CLIENT_ID').value,
              client_secret=Secret('MEETUP.CLIENT_SECRET').value,
              redirect_uri=Secret('MEETUP.REDIRECT_URI').value,
              show_log=True,
              test=False):
     self.logs = ['self.__init__']
     self.started = round(time.time())
     self.show_log = show_log
     self.group = group
     self.response = None
     self.email = email
     self.password = password
     self.client_id = client_id
     self.client_secret = client_secret,
     self.redirect_uri = redirect_uri
     self.setup_done = True if group else False
     self.help = 'https://www.meetup.com/meetup_api/docs/'
     self.test = test
示例#13
0
    def __init__(self, request=None):
        from _database.models import Event
        from _apis.models import Notify
        from django.http import JsonResponse
        from _setup.models import Config

        if not request or request.user.is_authenticated == False:
            response = JsonResponse(
                {'success': False, 'error': '--> Failed: User not logged in'})
            response.status_code = 403
        elif not request.GET.get('str_slug', None) or Event.objects.filter(boolean_approved=False, str_slug=request.GET.get('str_slug', None)).exists() == False:
            response = JsonResponse(
                {'success': False, 'error': '--> Failed: Result not found'})
            response.status_code = 404
        else:

            DOMAIN = Config('WEBSITE.DOMAIN').value
            # approve event and all upcoming ones
            event = Event.objects.filter(
                boolean_approved=False, str_slug=request.GET.get('str_slug', None)).first()

            upcoming_events = Event.objects.filter(
                boolean_approved=False, str_name_en_US=event.str_name_en_US).all()
            print('--> Approve all upcoming events')
            for event in upcoming_events:
                event.publish()

            # notify that event was approved and by who
            if 'HTTP_HOST' in request.META and request.META['HTTP_HOST'] == DOMAIN:
                Notify().send('✅'+str(request.user)+' approved the event "' +
                              event.str_name_en_US+'":\nhttps://'+DOMAIN+'/'+event.str_slug)

            response = JsonResponse({'success': True})
            response.status_code = 200

        self.value = response
示例#14
0
    def save(self, *args, **kwargs):
        # try:
        Log().print('event.save()')
        import urllib.parse
        from _database.models import Helper, Space, Person
        import bleach
        from _setup.models import Config
        import re
        from dateutil.parser import parse

        Log().print('--> auto change event to online if space closed when the event is happening')
        if self.str_location and not Config('EVENTS.ALLOW_IN_SPACE_EVENTS').value and Config('EVENTS.ALLOW_ONLINE_EVENTS').value:
            if Config('PHYSICAL_SPACE.TEMPORARY_LANDINGPAGE_HEADER.UP_TO_DATE').value:
                up_to_date = parse(
                    Config('PHYSICAL_SPACE.TEMPORARY_LANDINGPAGE_HEADER.UP_TO_DATE').value+' 00:00:00 +00:00')
                if self.datetime_start < up_to_date:
                    self.str_location = None
                    self.boolean_online_meetup = True

            else:
                self.str_location = None
                self.boolean_online_meetup = True

        Log().print('--> clean from scripts')
        if self.str_name_en_US:
            self.str_name_en_US = bleach.clean(self.str_name_en_US)
        if self.text_description_en_US:
            if not self.url_meetup_event:
                self.text_description_en_US = bleach.clean(
                    self.text_description_en_US)
        if self.text_description_he_IL:
            self.text_description_he_IL = bleach.clean(
                self.text_description_he_IL)
        if self.str_location:
            self.str_location = bleach.clean(
                self.str_location).replace('&lt;br&gt;', '<br>')
        if self.str_series_repeat_how_often:
            self.str_series_repeat_how_often = bleach.clean(
                self.str_series_repeat_how_often)
        if self.text_series_timing:
            self.text_series_timing = bleach.clean(self.text_series_timing)
        if self.str_crowd_size:
            self.str_crowd_size = bleach.clean(self.str_crowd_size)
        if self.str_welcomer:
            self.str_welcomer = bleach.clean(self.str_welcomer)
        if self.str_timezone:
            self.str_timezone = bleach.clean(self.str_timezone)

        self = Helper().RESULT__updateTime(self)
        if not self.str_slug:
            self.str_slug = 'event/'+(str(self.datetime_start.date(
            ))+'-' if self.datetime_start else '')+re.sub('[\W_]+', '', self.str_name_en_US.lower())
            counter = 0
            while Event.objects.filter(str_slug=self.str_slug).exists() == True:
                counter += 1
                self.str_slug = 'event/'+(str(self.datetime_start.date())+'-' if self.datetime_start else '')+re.sub(
                    '[\W_]+', '', self.str_name_en_US.lower())+str(counter)

        Log().print('--> Save lat/lon if not exist yet')
        if self.str_location and not self.float_lat:
            self.str_location, self.float_lat, self.float_lon = get_lat_lon_and_location(
                self.str_location)

        super(Event, self).save(*args, **kwargs)

        Log().print('--> Save hosts')
        if not self.many_hosts.exists():
            EVENTS_HOSTS_OVERWRITE = Config(
                'EVENTS.EVENTS_HOSTS_OVERWRITE').value
            # search in predefined event hosts in YOURHACKERSPACE
            for event_name in EVENTS_HOSTS_OVERWRITE:
                if event_name in self.str_name_en_US:
                    for host_name in EVENTS_HOSTS_OVERWRITE[event_name]:
                        host = Person.objects.QUERYSET__by_name(host_name)
                        if host:
                            self.many_hosts.add(host)
示例#15
0
    def save_wiki_photo(self, photo):
        from _apis.models import Scraper
        from _database.models import Photo
        from dateutil.parser import parse
        from datetime import datetime
        from _setup.models import Config

        if not self.url:
            self.log(
                '--> BASICS.WIKI.API_URL not found in config.json -> BASICS - Please add your WIKI_API_URL first.'
            )
            return

        if self.boolean_is_image(photo['url']) == True:
            # open url in selenium, test if image is on blocked list, else save low resolution image url
            browser = Scraper(photo['descriptionurl'],
                              scraper_type='selenium',
                              auto_close_selenium=False).selenium
            save_image = True
            try:
                pages_with_image = browser.find_element_by_id(
                    'mw-imagepage-section-linkstoimage').text.split('\n', 1)[1]
                for blocked_page in Config(
                        'BASICS.WIKI.PHOTOS_IGNORE_PAGES').value:
                    if blocked_page in pages_with_image:
                        save_image = False
                        break
            except:
                self.log(
                    '--> mw-imagepage-section-linkstoimage not found - coudlnt check if image url is blocked'
                )

            if save_image == False:
                self.log(
                    '--> Skipped photo. URL on WIKI.PHOTOS_IGNORE_PAGES list')

            elif Photo.objects.filter(
                    url_post=photo['descriptionurl']).exists() == True:
                self.log('--> Skipped photo. Already exists.')
                browser.close()
                return 'Skipped'

            else:
                try:
                    url_image = browser.find_element_by_class_name(
                        'mw-thumbnail-link').get_attribute('href')
                except:
                    url_image = photo['url']

                Photo(
                    text_description_en_US=photo['canonicaltitle']
                    if 'canonicaltitle' in photo else None,
                    url_image=url_image,
                    url_post=photo['descriptionurl'],
                    str_source='Wiki',
                    int_UNIXtime_created=round(
                        datetime.timestamp(parse(photo['timestamp']))),
                ).save()
                self.log('--> New photo saved')
                browser.close()

                return 'Saved'
示例#16
0
 def test_message(self):
     if Telegram().setup_done:
         messages = Config('UNITTESTS.TELEGRAM_TEST_MESSAGES').value
         selected_message = randint(0, len(messages) - 1)
         response = Telegram().message(messages[selected_message])
         self.assertEqual(response, True)
示例#17
0
    def __init__(self, request=None):
        from _apis.models import Notify
        from _database.models import Helper, Event, Space, Guilde, Person
        from _setup.models import Config
        from _setup.models import Secret
        from django.http import JsonResponse

        DOMAIN = Config('WEBSITE.DOMAIN').value

        int_UNIXtime_event_start = Helper().INT__UNIX_from_date_and_time_STR(
            request.POST.get('date', None), request.POST.get('time', None))
        int_minutes_duration = Helper().INT__duration_minutes(
            request.POST.get('duration', None))

        try:
            if request.FILES[
                    'images[0]'].content_type == 'image/jpeg' or request.FILES[
                        'images[0]'].content_type == 'image/png':
                image = request.FILES['images[0]']
            else:
                image = None
        except:
            image = None

        uploaded_photo_url = request.POST.get('photo', None)

        new_event = Event(
            boolean_approved=request.user.is_authenticated,
            str_name_en_US=request.POST.get('name_english', None),
            str_name_he_IL=request.POST.get('name_hebrew', None),
            int_UNIXtime_event_start=int_UNIXtime_event_start,
            int_minutes_duration=int_minutes_duration,
            int_UNIXtime_event_end=int_UNIXtime_event_start +
            (60 * int_minutes_duration),
            url_featured_photo=uploaded_photo_url
            if 'https' in uploaded_photo_url else None,
            image_featured_photo=image,
            text_description_en_US=request.POST.get('description_english',
                                                    None),
            text_description_he_IL=request.POST.get('description_hebrew',
                                                    None),
            one_space=Space.objects.QUERYSET__by_name(
                request.POST.get('space', None)),
            one_guilde=Guilde.objects.QUERYSET__by_name(
                request.POST.get('guilde', None)),
            str_crowd_size=request.POST.get('expected_crowd', None),
            str_welcomer=request.POST.get('event_welcomer', None),
            boolean_looking_for_volunteers=True if request.POST.get(
                'volunteers', None) == 'yes' else False)
        if request.POST.get('location', None):
            if request.POST.get('location',
                                None) != Config('BASICS.NAME').value:
                if request.POST.get('location', None).lower() == 'online':
                    new_event.boolean_online_meetup = True
                else:
                    new_event.str_location = request.POST.get('location', None)

        if request.POST.get('repeating', None):
            # if repeating, mark as such and auto generate new upcoming events with "update_database" command
            str_repeating_how_often = request.POST.get('repeating', None)
            str_repeating_up_to = request.POST.get('repeating_up_to', None)

            if str_repeating_how_often and str_repeating_how_often != '':
                new_event.int_series_startUNIX = new_event.int_UNIXtime_event_start
                new_event.str_series_repeat_how_often = str_repeating_how_often

            if str_repeating_up_to and str_repeating_up_to != '':
                new_event.int_series_endUNIX = Helper(
                ).INT__UNIX_from_date_and_time_STR(
                    str_repeating_up_to, request.POST.get('time', None))

        new_event.save()

        hosts = request.POST.get('hosts', None)
        if hosts:
            if hosts.startswith(','):
                hosts = hosts[1:]
            hosts = hosts.split(',')
            for host in hosts:
                new_event.many_hosts.add(Person.objects.by_url_discourse(host))

        # if loggedin user: share event to other platforms (Meetup, Discourse, etc.)
        if request.user.is_authenticated:
            new_event.create_discourse_event()
            new_event.create_meetup_event()

        # else (if event created via live website) inform via slack about new event and give community chance to delete it or confirm it
        elif 'HTTP_HOST' in request.META and request.META[
                'HTTP_HOST'] == DOMAIN:
            Notify().send(
                'A website visitor created a new event via our website.\n' +
                'If no one deletes it within the next 24 hours, it will be automatically published and appears in our website search'
                + (', meetup group' if Secret('MEETUP.ACCESS_TOKEN').
                   value else '') +
                (' and discourse' if Secret('DISCOURSE.API_KEY').exists ==
                 True else '') + '.\n' +
                '🚫-> Does this event already exist or is it spam? Open on the following event link and click "Delete event".\n'
                +
                '✅-> You have a user account for our website and want to publish the event directly? Open on the following event link and click "Approve event".\n'
                + 'https://' + DOMAIN + '/' + new_event.str_slug)
        else:
            print(
                '--> Request not sent via hackerspace domain. Skipped notifying via Slack.'
            )

        # if event is repeating, create upcoming instances
        new_event = new_event.create_upcoming_instances()

        # if user is signed in and event autoapproved - direct to event page, else show info
        self.value = JsonResponse({'url_next': '/' + new_event.str_slug})
示例#18
0
 def config(self):
     return {"FLICKR_URL": Config('SOCIAL.FLICKR_URL').value}
示例#19
0
    def __init__(self, backup_files, test=False):
        self.backup_files = backup_files
        self.test = test

        folders = os.listdir()
        folder_options = ''
        counter = 1
        backups = []
        for file_name in folders:
            if 'setup_backup__' in file_name:
                backups.append(file_name)
                if self.test and file_name == 'setup_backup__unittest.zip':
                    unittest_zip_counter = counter

                if counter > 1:
                    folder_options += ', '
                folder_options += str(counter)+' - ' + \
                    file_name.split('setup_backup__')[1].split('.zip')[0]
                counter += 1

        if counter == 1:
            Log().show_message('No backups found.')
        else:
            Log().show_message(
                'Which setup would you like to import? '+folder_options)
            selected_folder = unittest_zip_counter if self.test else input()

            # test if folder exist
            try:
                from zipfile import ZipFile

                selected_num = int(selected_folder)-1
                folder_name = backups[selected_num]

                # first delete existing files
                for file_path in self.backup_files:
                    if os.path.exists(file_path):
                        os.remove(file_path)

                # copy files into folder
                with ZipFile(folder_name, 'r') as zip:
                    # extracting all the files
                    zip.extractall()

            except:
                Log().show_message(
                    'ERROR: The folder doesnt exist. Please enter a correct number.')

            # make sure cronjobs are also setup
            Cronjob().setup()

            # test if superuser already exists
            User = get_user_model()
            if User.objects.count() == 0:
                username = Config('BASICS.NAME').value+'SuperMember'
                password = secrets.token_urlsafe(50)
                User.objects.create_superuser(username, None, password)
                self.secrets = Secret().value
                self.secrets['DJANGO']['ADMIN_USER']['USERNAME'] = username
                self.secrets['DJANGO']['ADMIN_USER']['PASSWORD'] = password
                with open('_setup/secrets.json', 'w') as outfile:
                    json.dump(self.secrets, outfile, indent=4)
                Log().show_message('Created admin user (see _setup/secrets.json for the login details)')

            Log().show_message('✅Done! Imported "'+folder_name.split('setup_backup__')
                               [1].split('.zip')[0] + '" ('+self.get_size(folder_name)+') and created cronjobs to keep your database up to date!')
示例#20
0
 def config(self):
     return {
         "GOOGLE_PHOTOS_ALBUM_URLS":
         Config('SOCIAL.GOOGLE_PHOTOS_ALBUM_URLS').value
     }
示例#21
0
 def config(self):
     return {"username": Config('SOCIAL.SOCIAL_NETWORKS', username_for='twitter.com').value, "hashtag": Config('SOCIAL.HASHTAG').value}
示例#22
0
    def __init__(self, access_token, group, event, announce, publish_status):
        self.logs = ['self.__init__']
        self.started = round(time.time())
        self.access_token = access_token
        self.group = group

        # API Doc: https://www.meetup.com/meetup_api/docs/:urlname/events/#create
        self.log('create()')

        if not self.access_token:
            self.log('--> No MEETUP.ACCESS_TOKEN')
            self.log('--> return None')
            return None

        response = requests.post(
            'https://api.meetup.com/' + self.group + '/events',
            params={
                'access_token':
                self.access_token,
                'sign':
                True,
                'announce':
                announce,
                'publish_status':
                publish_status,  # draft or published
                'description':
                event.text_description_en_US,
                'duration':
                event.int_minutes_duration * 60 * 1000,
                'event_hosts':
                None,  # TODO figure out meetup user IDs and how to add them here
                'fee': {
                    'accepts': None,  # TODO add option for paid events later
                    'amount': None,
                    'currency': None,
                    'refund_policy': None
                },
                'guest_limit':
                2,  # from 0 to 2
                'how_to_find_us':
                Config('PHYSICAL_SPACE.ADDRESS.HOW_TO_FIND_US__english').value,
                'lat':
                event.float_lat,
                'lon':
                event.float_lon,
                'name':
                event.str_name_en_US,
                'self_rsvp':
                False,
                'time':
                event.int_UNIXtime_event_start * 1000,
                'venue_id':
                None,  # TODO figure out how to get venue id
                'venue_visibility':
                None  # TODO
            })

        if response.status_code == 201:
            event.url_meetup_event = response.json()['link']
            event.save()
            self.log('--> return event')
            self.value = event
        else:
            self.log('--> ' + str(response.status_code) + ' response: ' +
                     str(response.json()))
            self.value = None
示例#23
0
class Event(models.Model):
    from _setup.models import Config
    from _database.models.event_set import EventSet

    HACKERSPACE_ADDRESS = Config('PHYSICAL_SPACE.ADDRESS').value
    LAT_LON = Config('PHYSICAL_SPACE.LAT_LON').value
    CROWD_SIZE = Config('EVENTS.CROWD_SIZE').value

    ADDRESS_STRING = Config('BASICS.NAME').value+'<br>' + \
        (HACKERSPACE_ADDRESS['STREET'] if HACKERSPACE_ADDRESS['STREET'] else '')+'<br' + \
        (HACKERSPACE_ADDRESS['ZIP'] if HACKERSPACE_ADDRESS['ZIP'] else '')+(', '+HACKERSPACE_ADDRESS['CITY'] if HACKERSPACE_ADDRESS['CITY'] else '') + \
        (', '+HACKERSPACE_ADDRESS['STATE'] if HACKERSPACE_ADDRESS['STATE'] else '')+(
            ', '+HACKERSPACE_ADDRESS['COUNTRYCODE'] if HACKERSPACE_ADDRESS['COUNTRYCODE'] else '')
    SMALL = 'small'
    MEDIUM = 'medium'
    LARGE = 'large'
    EVENT_CROWD_SIZE = (
        (SMALL, CROWD_SIZE['SMALL']),
        (MEDIUM, CROWD_SIZE['MEDIUM']),
        (LARGE, CROWD_SIZE['LARGE']),
    )

    WEEKLY = 'weekly'
    BIWEEKLY = 'biweekly'
    MONTHLY = 'monthly'
    REPEAT_HOW_OFTEN = (
        (WEEKLY, 'weekly'),
        (BIWEEKLY, 'biweekly'),
        (MONTHLY, 'monthly'),
    )

    objects = EventSet.as_manager()
    str_name_en_US = models.CharField(
        max_length=250, blank=True, null=True, verbose_name='Name en-US')
    str_name_he_IL = models.CharField(
        max_length=250, blank=True, null=True, verbose_name='Name he-IL')
    str_slug = models.CharField(
        max_length=250, unique=True, blank=True, null=True)
    boolean_approved = models.BooleanField(default=True)
    int_UNIXtime_event_start = models.IntegerField(
        blank=True, null=True, verbose_name='Event start (UNIX time)')
    int_minutes_duration = models.IntegerField(
        default=60, verbose_name='Duration in minutes')
    int_UNIXtime_event_end = models.IntegerField(
        blank=True, null=True, verbose_name='Event end (UNIX time)')

    url_featured_photo = models.URLField(
        max_length=200, blank=True, null=True, verbose_name='Photo URL')
    image_featured_photo = models.ImageField(
        upload_to='event_images', blank=True, null=True, verbose_name='Photo')
    text_description_en_US = models.TextField(
        blank=True, null=True, verbose_name='Description en-US')
    text_description_he_IL = models.TextField(
        blank=True, null=True, verbose_name='Description he-IL')

    boolean_online_meetup = models.BooleanField(default=False)
    str_location = models.CharField(
        max_length=250, default=ADDRESS_STRING, verbose_name='Location', blank=True, null=True)
    float_lat = models.FloatField(
        default=LAT_LON[0], blank=True, null=True, verbose_name='Lat')
    float_lon = models.FloatField(
        default=LAT_LON[1], blank=True, null=True, verbose_name='Lon')

    one_space = models.ForeignKey(
        'Space', related_name="o_space", default=None, blank=True, null=True, on_delete=models.SET_NULL, verbose_name='Space')
    one_guilde = models.ForeignKey(
        'Guilde', related_name="o_guilde", default=None, blank=True, null=True, on_delete=models.SET_NULL, verbose_name='Guilde')
    many_hosts = models.ManyToManyField(
        'Person', related_name="m_persons", blank=True, verbose_name='Hosts')

    boolean_looking_for_volunteers = models.BooleanField(default=False)

    str_series_id = models.CharField(
        max_length=250, blank=True, null=True, verbose_name='Series ID')
    int_series_startUNIX = models.IntegerField(
        blank=True, null=True, verbose_name='Series Start (UNIX time)')
    int_series_endUNIX = models.IntegerField(
        blank=True, null=True, verbose_name='Series End (UNIX time)')
    str_series_repeat_how_often = models.CharField(
        max_length=50, choices=REPEAT_HOW_OFTEN, blank=True, null=True, verbose_name='Series How often repeating?')
    text_series_timing = models.TextField(
        blank=True, null=True)  # json saved as text

    str_crowd_size = models.CharField(
        max_length=250, choices=EVENT_CROWD_SIZE, default=SMALL, verbose_name='Expected crowd size')
    str_welcomer = models.CharField(
        max_length=250, blank=True, null=True, verbose_name='(for large events) Who welcomes people at the door?')

    url_meetup_event = models.URLField(
        max_length=250, blank=True, null=True, verbose_name='Meetup URL')
    url_discourse_event = models.URLField(
        max_length=250, blank=True, null=True, verbose_name='discourse URL')

    int_UNIXtime_created = models.IntegerField(blank=True, null=True)
    int_UNIXtime_updated = models.IntegerField(blank=True, null=True)
    str_timezone = models.CharField(
        max_length=100, default=Config('PHYSICAL_SPACE.TIMEZONE_STRING').value, blank=True, null=True, verbose_name='Timezone')

    def __str__(self):
        if not self.datetime_range:
            return self.str_name_en_US
        return self.str_name_en_US+' | '+self.datetime_range

    def INT__getWeekday(self, number):
        Log().print('INT__getWeekday(number={})'.format(number))
        days = {
            0: 'Mon',
            1: 'Tue',
            2: 'Wed',
            3: 'Thu',
            4: 'Fri',
            5: 'Sat',
            6: 'Sun',
        }
        return days[number]

    def RESULT__extractSpace(self, json_meetup_result):
        Log().print('RESULT__extractSpace(json_meetup_result)')
        from _database.models import Space
        from _setup.models import Config

        if 'how_to_find_us' in json_meetup_result:
            spaces = Space.objects.all()

            for space in spaces.iterator():
                if space.str_name_en_US.lower() in json_meetup_result['how_to_find_us'].lower():
                    return space

        # else...
        EVENTS_SPACES_OVERWRITE = Config(
            'EVENTS.EVENTS_SPACES_OVERWRITE').value
        for field in EVENTS_SPACES_OVERWRITE:
            if field in json_meetup_result['name']:
                return Space.objects.QUERYSET__by_name(EVENTS_SPACES_OVERWRITE[field])
        else:
            return Space.objects.QUERYSET__by_name(Config('EVENTS.EVENTS_SPACE_DEFAULT').value)

    def RESULT__extractGuilde(self, json_meetup_result):
        Log().print('RESULT__extractGuilde(json_meetup_result)')
        from _database.models import Guilde
        from _setup.models import Config

        EVENTS_GUILDES_OVERWRITE = Config(
            'EVENTS.EVENTS_GUILDES_OVERWRITE').value

        for str_keyword in EVENTS_GUILDES_OVERWRITE:
            if str_keyword in json_meetup_result['name']:
                Log().print('--> {} found in result.name'.format(str_keyword))
                Log().print('--> return guilde')
                return Guilde.objects.filter(str_name_en_US=EVENTS_GUILDES_OVERWRITE[str_keyword]).first()
        else:
            Log().print('--> return None')
            return None

    def INT__timezoneToOffset(self, timezone_name):
        Log().print('INT__timezoneToOffset(timezone_name={})'.format(timezone_name))
        from datetime import datetime
        import pytz

        Log().print('--> return INT')
        return int(datetime.now(pytz.timezone(timezone_name)).utcoffset().total_seconds()*1000)

    def LIST__offsetToTimezone(self, offset_ms):
        Log().print('LIST__offsetToTimezone(offset_ms={})'.format(offset_ms))
        from datetime import datetime
        import pytz

        now = datetime.now(pytz.utc)  # current time
        Log().print('--> return LIST')
        return [tz.zone for tz in map(pytz.timezone, pytz.all_timezones_set)
                if now.astimezone(tz).utcoffset().total_seconds()*1000 == offset_ms][0]

    def STR__extractTimezone(self, json_meetup_result):
        Log().print('STR__extractTimezone(json_meetup_result)')
        from _setup.models import Config
        TIMEZONE_STRING = Config('PHYSICAL_SPACE.TIMEZONE_STRING').value

        if 'utc_offset' in json_meetup_result and json_meetup_result['utc_offset'] != self.INT__timezoneToOffset(TIMEZONE_STRING):
            return self.LIST__offsetToTimezone(json_meetup_result['utc_offset'])

        Log().print('--> return STR')
        return TIMEZONE_STRING

    def get_lat_lon_and_location(self, str_location):
        from geopy.geocoders import Nominatim
        from geopy.exc import GeocoderTimedOut
        from _setup.models import Config

        geolocator = Nominatim(user_agent=Config('BASICS.NAME').value.lower())
        str_location = str_location.replace('\n', ', ')
        float_lat = None
        float_lon = None
        while float_lat == None and len(str_location) > 0:
            try:
                location = geolocator.geocode(str_location)

                float_lat, float_lon = location.latitude, location.longitude
            except GeocoderTimedOut:
                print('GeocoderTimedOut! This might be solved by turning off your VPN.')
                break
            except:
                str_location = ','.join(str_location.split(',')[:-1])

        return str_location, float_lat, float_lon

    def createEvent(self, event):
        Log().print('createEvent(event)')
        from _setup.models import Config
        from dateutil.parser import parse
        from datetime import datetime

        HACKERSPACE_NAME = Config('BASICS.NAME').value
        HACKERSPACE_ADDRESS = Config('PHYSICAL_SPACE.ADDRESS').value
        str_location_name = event['venue']['name'] if 'venue' in event and event['venue']['name'] and event[
            'venue']['name'] != HACKERSPACE_NAME else HACKERSPACE_NAME
        str_location_street = event['venue']['address_1'] if 'venue' in event and event['venue']['name'] and event[
            'venue']['name'] != HACKERSPACE_NAME else HACKERSPACE_ADDRESS['STREET']
        str_location_zip = event['venue']['zip'] if 'venue' in event and 'zip' in event['venue'] and event['venue']['name'] and event[
            'venue']['name'] != HACKERSPACE_NAME else HACKERSPACE_ADDRESS['ZIP']
        str_location_city = event['venue']['city'] if 'venue' in event and 'city' in event['venue'] and event['venue']['name'] and event[
            'venue']['name'] != HACKERSPACE_NAME else HACKERSPACE_ADDRESS['CITY']
        str_location_countrycode = event['venue']['country'].upper() if 'venue' in event and 'country' in event['venue'] and event['venue']['name'] and event[
            'venue']['name'] != HACKERSPACE_NAME else HACKERSPACE_ADDRESS['COUNTRYCODE']

        Event().create(json_content={
            'str_name_en_US': event['name'] if 'name' in event else event['title'],
            'int_UNIXtime_event_start': round(event['time']/1000) if 'time' in event else parse(event['event']['start']).timestamp(),
            'int_UNIXtime_event_end': round(event['time']/1000)+(event['duration']/1000) if 'time' in event else parse(event['event']['end']).timestamp() if 'end' in event['event'] else parse(event['event']['start']).timestamp()+(120*60),
            'int_minutes_duration': ((event['duration']/1000)/60) if 'duration' in event else round(
                (parse(event['event']['end']).timestamp() - parse(event['event']['start']).timestamp())/1000) if 'end' in event['event'] else 120,
            'url_featured_photo': event['featured_photo']['photo_link'] if 'featured_photo' in event else event['image_url'] if 'image_url' in event and event['image_url'] else None,
            'text_description_en_US': event['description'],
            'str_location': str_location_name+'\n'+str_location_street+'\n'+str_location_zip+', '+str_location_city+', '+str_location_countrycode,
            'one_space': self.RESULT__extractSpace(event),
            'one_guilde': self.RESULT__extractGuilde(event),
            'str_series_id': event['series']['id'] if 'series' in event else None,
            'int_series_startUNIX': round(
                event['series']['start_date'] / 1000) if 'series' in event and 'start_date' in event['series'] else None,
            'int_series_endUNIX': round(
                event['series']['end_date'] / 1000) if 'series' in event and 'end_date' in event['series'] else None,
            'text_series_timing': 'weekly: '+str(event['series']['weekly']) if 'series' in event and 'weekly' in event['series'] else 'monthly: ' +
            str(event['series']['monthly']
                ) if 'series' in event and 'monthly' in event['series'] else None,
            'url_meetup_event': event['link'] if 'link' in event else None,
            'int_UNIXtime_created': event['created'] if 'created' in event else parse(event['created_at']).timestamp(),
            'int_UNIXtime_updated': event['updated'] if 'updated' in event else parse(event['last_posted_at']).timestamp(),
            'str_timezone': self.STR__extractTimezone(event)
        }
        )

    def RESULT__next_event(self):
        Log().print('event.RESULT__next_event()')
        Log().print('--> return QUERYSET')
        return Event.objects.QUERYSET__upcoming().filter(str_name_en_US=self.str_name_en_US, str_series_repeat_how_often=self.str_series_repeat_how_often).exclude(str_slug=self.str_slug).first()

    @property
    def str_menu_heading(self):
        return 'menu_h_events'

    @property
    def series(self):
        return Event.objects.filter(str_name_en_US=self.str_name_en_US, str_series_repeat_how_often=self.str_series_repeat_how_often).order_by('int_UNIXtime_event_start')

    @property
    def str_series(self):
        import json

        if not self.text_series_timing:
            return None

        text_series_timing = self.text_series_timing.replace(
            'weekly: ', '"weekly": ').replace('monthly: ', '"monthly": ').replace("'", '"')
        json_series_timing = json.loads('{'+text_series_timing+'}')
        if 'weekly' in json_series_timing:
            weekday_num = json_series_timing['weekly']['days_of_week'][0]
            return 'every '+(json_series_timing['weekly']['interval']+'nd' if json_series_timing['weekly']['interval'] > 1 else '')+self.INT__getWeekday(weekday_num)

        if 'monthly' in json_series_timing:
            return 'every month'

    @property
    def json_data(self):
        return {
            'str_name_en_US': self.str_name_en_US,
            'url_hackerspace_event': 'https://'+Config('WEBSITE.DOMAIN').value+'/'+self.str_slug,
            'datetime_start': str(self.datetime_start),
            'datetime_end': str(self.datetime_end),
            'str_timezone': self.str_timezone,
            'int_UNIXtime_event_start': self.int_UNIXtime_event_start,
            'int_minutes_duration': self.int_minutes_duration,
            'int_UNIXtime_event_end': self.int_UNIXtime_event_end,
            'url_featured_photo': self.url_featured_photo,
            'text_description_en_US': self.text_description_en_US,
            'str_location': self.str_location,
            'float_lat': self.float_lat,
            'float_lon': self.float_lon,
            'str_space': self.one_space.str_name_en_US if self.one_space else None,
            'str_guilde': self.one_guilde.str_name_en_US if self.one_guilde else None,
            'list_hosts': [x.str_name_shortened for x in self.many_hosts.all()],
            'int_series_startUNIX': self.int_series_startUNIX,
            'int_series_endUNIX': self.int_series_endUNIX,
            'str_series_repeat_how_often': self.str_series_repeat_how_often,
            'str_crowd_size': self.str_crowd_size,
            'str_welcomer': self.str_welcomer,
            'url_meetup_event': self.url_meetup_event,
            'url_discourse_event': self.url_discourse_event,
            'int_UNIXtime_created': self.int_UNIXtime_created,
            'int_UNIXtime_updated': self.int_UNIXtime_updated,
        }

    @property
    def str_relative_time(self):
        if hasattr(self, 'str_relative_time_value'):
            return self.str_relative_time_value

        import time

        if not self.int_UNIXtime_event_start:
            self.str_relative_time_value = None
        else:

            timestamp = self.int_UNIXtime_event_start

            # show if event is over
            if self.int_UNIXtime_event_end < time.time():
                self.str_relative_time_value = 'Ended'

            # if date within next 5 minutes
            elif timestamp < time.time() and self.int_UNIXtime_event_end > time.time():
                self.str_relative_time_value = 'Now'

            # in next 60 minutes
            elif timestamp <= time.time()+(60*60):
                minutes_in_future = int((timestamp - time.time())/60)
                self.str_relative_time_value = 'in ' + \
                    str(minutes_in_future)+' minute' + \
                    ('s' if minutes_in_future > 1 else '')

            # in next 12 hours
            elif timestamp <= time.time()+(60*60*12):
                hours_in_future = int(((timestamp - time.time())/60)/60)
                self.str_relative_time_value = 'in ' + \
                    str(hours_in_future)+' hour' + \
                    ('s' if hours_in_future > 1 else '')

            # else if in next 6 days, return name of day
            elif timestamp <= time.time()+(60*60*24*6):
                name_of_weekday = self.datetime_start.strftime("%A")
                self.str_relative_time_value = name_of_weekday

            else:
                self.str_relative_time_value = None

        return self.str_relative_time_value

    @property
    def videocall_now(self):
        if self.boolean_online_meetup and self.str_relative_time == 'Now':
            return True
        else:
            return False

    @property
    def str_relative_publish_time(self):
        import time

        int_UNIX_published_in = self.int_UNIXtime_created+(24*60*60)

        # in next 60 minutes
        if int_UNIX_published_in <= time.time()+(60*60):
            minutes_in_future = int((int_UNIX_published_in - time.time())/60)
            return 'in '+str(minutes_in_future)+' minute'+('s' if minutes_in_future > 1 else '')

        # in next 24 hours
        elif int_UNIX_published_in <= time.time()+(24*60*60):
            hours_in_future = int(
                ((int_UNIX_published_in - time.time())/60)/60)
            return 'in '+str(hours_in_future)+' hour'+('s' if hours_in_future > 1 else '')

    @property
    def datetime_start(self):
        import pytz
        from datetime import datetime

        if hasattr(self, 'datetime_start_value'):
            return self.datetime_start_value

        if not self.int_UNIXtime_event_start:
            return None
        local_timezone = pytz.timezone(self.str_timezone)
        local_time = datetime.fromtimestamp(
            self.int_UNIXtime_event_start, local_timezone)

        self.datetime_start_value = local_time
        return self.datetime_start_value

    @property
    def datetime_end(self):
        from datetime import timedelta

        if not self.datetime_start:
            return None

        return self.datetime_start+timedelta(minutes=self.int_minutes_duration)

    @property
    def time_range(self):
        if not (self.datetime_start and self.datetime_end):
            return None

        start_time = self.datetime_start.strftime(
            '%I:%M %p') if self.datetime_start.minute > 0 else self.datetime_start.strftime('%I %p')
        if self.datetime_start.strftime('%p') == self.datetime_end.strftime('%p'):
            start_time = start_time[:-3]
        end_time = self.datetime_end.strftime(
            '%I:%M %p') if self.datetime_end.minute > 0 else self.datetime_end.strftime('%I %p')

        # remove zeros to shorten text
        if start_time.startswith('0'):
            start_time = start_time[1:]
        if end_time.startswith('0'):
            end_time = end_time[1:]

        # if runtime > 24 hours, show num of days instead
        return '⏰'+start_time+(' - ' + end_time if self.int_minutes_duration < (24*60) else ' | '+str(round(self.int_minutes_duration/60/24))+' days')

    @property
    def time_range_text(self):
        return self.time_range.replace('⏰', '')

    @property
    def datetime_range(self):
        if not (self.datetime_start and self.datetime_end):
            return None

        month = self.datetime_start.strftime('%b')
        day_num = str(self.datetime_start.day)

        # if runtime > 24 hours, show num of days instead
        return '🗓'+month+' '+day_num+' | '+self.time_range

    @property
    def datetime_range_text(self):
        return self.datetime_range.replace('⏰', '').replace('🗓', '')

    @property
    def repeating(self):
        import calendar

        if not self.str_series_repeat_how_often:
            return False

        if self.str_series_repeat_how_often == 'weekly':
            day_of_week = calendar.day_name[self.datetime_start.weekday()]
            how_often = 'Every '+day_of_week

        elif self.str_series_repeat_how_often == 'biweekly':
            day_of_week = calendar.day_name[self.datetime_start.weekday()]
            how_often = 'Every 2nd '+day_of_week

        elif self.str_series_repeat_how_often == 'monthly':
            date_of_month = self.datetime_start.day
            if date_of_month == 1:
                date_of_month = str(date_of_month)+'st'
            elif date_of_month == 2:
                date_of_month = str(date_of_month)+'nd'
            elif date_of_month == 3:
                date_of_month = str(date_of_month)+'rd'
            else:
                date_of_month = str(date_of_month)+'th'
            how_often = 'Every month on the '+date_of_month
        return how_often

    def save_social_media_image(self):
        Log().print('event.save_social_media_image()')
        import time
        import asyncio
        from pyppeteer import launch

        filename = 'social_image'+str(time.time())+'.png'

        async def main():
            browser = await launch(headless=True, ignoreHTTPSErrors=True, args=['--no-sandbox'])
            page = await browser.newPage()
            await page.emulate({'viewport': {'width': 500, 'height': 500}})
            await page.goto('https://'+Config('WEBSITE.DOMAIN').value+'/'+self.str_slug+'/banner')
            await page.screenshot({'path': filename})
            await browser.close()

        asyncio.get_event_loop().run_until_complete(main())

        return filename

    def publish(self):
        Log().print('event.publish()')
        self.boolean_approved = True
        super(Event, self).save()

        self.create_discourse_event()
        # self.create_meetup_event()

    def create_upcoming_instances(self):
        Log().print('event.create_upcoming_instances()')
        import time
        if not self.str_series_repeat_how_often:
            Log().print('--> return')
            return self

        Log().print('--> Define days_increase')
        if self.str_series_repeat_how_often == 'weekly':
            days_increase = 7

        elif self.str_series_repeat_how_often == 'biweekly':
            days_increase = 14

        elif self.str_series_repeat_how_often == 'monthly':
            days_increase = 30

        Log().print('--> Define start & end time of while statement')
        original_pk = self.pk
        original_slug = self.str_slug
        original_event_start = self.int_UNIXtime_event_start
        original_event_end = self.int_UNIXtime_event_end

        int_UNIX_time = self.int_series_startUNIX+(days_increase*24*60*60)
        int_UNIX_end = time.time()+(2*30*24*60*60)

        self.int_UNIXtime_event_start += (days_increase*24*60*60)
        self.int_UNIXtime_event_end += (days_increase*24*60*60)
        hosts = self.many_hosts.all()

        if self.int_series_endUNIX and self.int_series_endUNIX < int_UNIX_end:
            int_UNIX_end = self.int_series_endUNIX

        while int_UNIX_time < int_UNIX_end:
            Log().print('--> Create event on UNIX time '+str(int_UNIX_time))
            self.pk = None
            self.str_slug = None
            self.save()

            Log().print('--> Add many hosts for new instance')
            for host in hosts:
                self.many_hosts.add(host)

            int_UNIX_time += (days_increase*24*60*60)
            self.int_UNIXtime_event_start += (days_increase*24*60*60)
            self.int_UNIXtime_event_end += (days_increase*24*60*60)

        Log().print('--> Back to original values of first event')
        self.pk = original_pk
        self.str_slug = original_slug
        self.int_UNIXtime_event_start = original_event_start
        self.int_UNIXtime_event_end = original_event_end
        return self

    def create_discourse_event(self):
        Log().print('event.create_discourse_event()')
        from _apis.models import create_post
        from django.template.loader import get_template

        if self.str_series_repeat_how_often:
            name = (self.repeating + ' | '+self.time_range_text +
                    ' | '+self.str_name_en_US)
        else:
            name = self.datetime_range_text+' | '+self.str_name_en_US

        self.url_discourse_event = create_post(
            name,
            get_template('components/discourse/event_post.html').render({
                'result': self
            }),
            Config('EVENTS.DISCOURSE_EVENTS_CATEGORY').value)
        super(Event, self).save()
        Log().print('--> return event')
        return self

    def delete_discourse_event(self):
        Log().print('event.delete_discourse_event()')
        from _apis.models import delete_post
        if self.url_discourse_event:
            deleted = delete_post(self.url_discourse_event)
            if deleted == True:
                self.url_discourse_event = None
            super(Event, self).save()
        Log().print('--> return event')
        return self

    def delete_photo(self):
        Log().print('event.delete_photo()')
        from _apis.models import Aws
        # if url_featured_photo - delete on AWS
        if self.url_featured_photo and 'amazonaws.com' in self.url_featured_photo:
            success = Aws().delete(
                self.url_featured_photo.split('amazonaws.com/')[1])
            if success:
                self.url_featured_photo = None
                super(Event, self).save()
                return self
            else:
                return self

        # else delete in local folder
        elif self.image_featured_photo:
            self.image_featured_photo.delete(save=True)
            return self

    def delete(self):
        Log().print('event.delete()')
        # delete discourse posts
        self.delete_discourse_event()

        # delete uploaded photo
        self.delete_photo()

        super(Event, self).delete()
        Log().print('--> Deleted')

    def delete_series(self):
        Log().print('event.delete_series()')
        # delete in database
        if self.str_series_repeat_how_often:
            # if series, delete all in series
            Event.objects.filter(str_name_en_US=self.str_name_en_US,
                                 str_series_repeat_how_often=self.str_series_repeat_how_often).delete()
            Log().print('--> Deleted')
        else:
            Log().print('--> Not a series. Skipped deleting.')

    def create_meetup_event(self):
        from _apis.models import Meetup
        returned_event = Meetup().create(self)
        if returned_event:
            self = returned_event
        return self

    def save(self, *args, **kwargs):
        # try:
        Log().print('event.save()')
        import urllib.parse
        from _database.models import Helper, Space, Person
        import bleach
        from _setup.models import Config
        import re
        from dateutil.parser import parse

        Log().print('--> auto change event to online if space closed when the event is happening')
        if self.str_location and not Config('EVENTS.ALLOW_IN_SPACE_EVENTS').value and Config('EVENTS.ALLOW_ONLINE_EVENTS').value:
            if Config('PHYSICAL_SPACE.TEMPORARY_LANDINGPAGE_HEADER.UP_TO_DATE').value:
                up_to_date = parse(
                    Config('PHYSICAL_SPACE.TEMPORARY_LANDINGPAGE_HEADER.UP_TO_DATE').value+' 00:00:00 +00:00')
                if self.datetime_start < up_to_date:
                    self.str_location = None
                    self.boolean_online_meetup = True

            else:
                self.str_location = None
                self.boolean_online_meetup = True

        Log().print('--> clean from scripts')
        if self.str_name_en_US:
            self.str_name_en_US = bleach.clean(self.str_name_en_US)
        if self.text_description_en_US:
            if not self.url_meetup_event:
                self.text_description_en_US = bleach.clean(
                    self.text_description_en_US)
        if self.text_description_he_IL:
            self.text_description_he_IL = bleach.clean(
                self.text_description_he_IL)
        if self.str_location:
            self.str_location = bleach.clean(
                self.str_location).replace('&lt;br&gt;', '<br>')
        if self.str_series_repeat_how_often:
            self.str_series_repeat_how_often = bleach.clean(
                self.str_series_repeat_how_often)
        if self.text_series_timing:
            self.text_series_timing = bleach.clean(self.text_series_timing)
        if self.str_crowd_size:
            self.str_crowd_size = bleach.clean(self.str_crowd_size)
        if self.str_welcomer:
            self.str_welcomer = bleach.clean(self.str_welcomer)
        if self.str_timezone:
            self.str_timezone = bleach.clean(self.str_timezone)

        self = Helper().RESULT__updateTime(self)
        if not self.str_slug:
            self.str_slug = 'event/'+(str(self.datetime_start.date(
            ))+'-' if self.datetime_start else '')+re.sub('[\W_]+', '', self.str_name_en_US.lower())
            counter = 0
            while Event.objects.filter(str_slug=self.str_slug).exists() == True:
                counter += 1
                self.str_slug = 'event/'+(str(self.datetime_start.date())+'-' if self.datetime_start else '')+re.sub(
                    '[\W_]+', '', self.str_name_en_US.lower())+str(counter)

        Log().print('--> Save lat/lon if not exist yet')
        if self.str_location and not self.float_lat:
            self.str_location, self.float_lat, self.float_lon = get_lat_lon_and_location(
                self.str_location)

        super(Event, self).save(*args, **kwargs)

        Log().print('--> Save hosts')
        if not self.many_hosts.exists():
            EVENTS_HOSTS_OVERWRITE = Config(
                'EVENTS.EVENTS_HOSTS_OVERWRITE').value
            # search in predefined event hosts in YOURHACKERSPACE
            for event_name in EVENTS_HOSTS_OVERWRITE:
                if event_name in self.str_name_en_US:
                    for host_name in EVENTS_HOSTS_OVERWRITE[event_name]:
                        host = Person.objects.QUERYSET__by_name(host_name)
                        if host:
                            self.many_hosts.add(host)
        # except:
        #     Log().print('--> ERROR: coudlnt save event - '+str(self))

    def create(self, json_content):
        Log().print('event.create(json_content)')
        try:
            obj = Event.objects.get(
                str_name_en_US=json_content['str_name_en_US'],
                int_UNIXtime_event_start=json_content['int_UNIXtime_event_start']
            )
            for key, value in json_content.items():
                setattr(obj, key, value)
            super(Event, obj).save()
            Log().print('--> Updated "'+obj.str_name_en_US +
                        ' | ' + obj.datetime_range+'"')

        except Event.DoesNotExist:
            obj = Event(**json_content)
            obj.save()
            Log().print('--> Created "'+obj.str_name_en_US +
                        ' | ' + obj.datetime_range+'"')

    # Noisebridge specific
    def announce_via_marry(self):
        Log().print('event.announce_via_marry()')
        import time
        from _apis.models import MarrySpeak

        start_time = self.str_relative_time if self.int_UNIXtime_event_start < time.time(
        )+(60*60) else self.datetime_start.strftime('%I %p')
        if start_time == 'Now':
            MarrySpeak().speak(str(self.str_name_en_US)+' is happening now', None)
        else:
            MarrySpeak().speak(str(self.str_name_en_US)+' starts at '+start_time, None)

    def announce_via_flaschentaschen(self):
        Log().print('event.announce_via_flaschentaschen()')
        from _apis.models import Flaschentaschen
        Flaschentaschen().showText(self)
示例#24
0
 def config(self):
     return {"group": Config('EVENTS.MEETUP_GROUP').value}
示例#25
0
    def import_photos(self, WIKI_API_URL=Config('BASICS.WIKI.API_URL').value):
        # API documentation: https://www.mediawiki.org/wiki/API:Allimages
        self.log('import_photos()')
        from _database.models import Photo
        from _setup.models import Config
        from _setup.models import Log
        import requests
        import time

        if WIKI_API_URL:
            Log().show_message(
                '✅ Found BASICS.WIKI.API_URL - Start importing photos from your Wiki ...'
            )
            time.sleep(2)
            if requests.get(WIKI_API_URL).status_code != 200:
                Log().show_message(
                    'WARNING: I can\'t access your Wiki. Is the API_URL correct? Will skip importing photos from your Wiki for now.'
                )
                time.sleep(4)
                return
        else:
            Log().show_message(
                'WARNING: Can\'t find BASICS.WIKI.API_URL in your config.json. Will skip importing photos from your Wiki for now.'
            )
            time.sleep(4)
            return

        parameter = {
            'action': 'query',
            'format': 'json',
            'list': 'allimages',
            'list': 'allimages',
            'aisort': 'timestamp',
            'aidir': 'descending',
            'ailimit': '500' if not self.test else '5',
            'aiminsize':
            '50000',  # minimum 50kb size, to filter out small logos/icons
            'aiprop': 'timestamp|canonicaltitle|url|user'
        }
        response_json = requests.get(WIKI_API_URL, params=parameter).json()

        skipped_photos_counter = 0

        # for every photo...
        for photo in response_json['query']['allimages']:
            if skipped_photos_counter < 5:
                status = self.save_wiki_photo(photo)
                if status == 'Skipped':
                    skipped_photos_counter += 1

        if not self.test:
            while 'continue' in response_json and 'aicontinue' in response_json[
                    'continue'] and skipped_photos_counter < 5:
                response_json = requests.get(
                    WIKI_API_URL,
                    params={
                        **parameter,
                        **{
                            'aicontinue': response_json['continue']['aicontinue']
                        }
                    }).json()

                for photo in response_json['query']['allimages']:
                    status = self.save_wiki_photo(photo)
                    if status == 'Skipped':
                        skipped_photos_counter += 1

        if skipped_photos_counter >= 5:
            self.log('No new photos it seems.')

        self.log('Complete! All photos processed! Now {} photos'.format(
            Photo.objects.count()))
示例#26
0
 def import_from_meetup(self, slug=Config('EVENTS.MEETUP_GROUP').value):
     from _database.models import Event
     from _apis.models import Meetup
     events = Meetup(slug).events(maximum_num_events=1000)
     for event in events:
         Event().create(json_content=event)
示例#27
0
    def query(self, query, filter_name=None):
        self.log('query()')
        from _apis.models import Discourse, MediaWiki
        from _database.models import Person, Event, MeetingNote, Guilde, Machine, Space, Consensus, Project
        from _setup.models import Config

        if not query:
            return []

        if filter_name and filter_name == 'hosts':
            return Person.objects.filter(
                Q(str_name_en_US__icontains=query)
                | Q(url_discourse__icontains=query))

        # search in database
        events = Event.objects.filter(
            Q(boolean_approved=True)
            & (Q(str_name_en_US__icontains=query)
               | Q(text_description_en_US__icontains=query))
        ).QUERYSET__upcoming()

        if filter_name == 'events':
            return events
        else:
            events = events.LIST__search_results()[:5]

        # search in social network accounts
        networks = [{
            'icon': x['name'].lower(),
            'name': x['name'],
            'url': x['url'],
        } for x in Config('SOCIAL.SOCIAL_NETWORKS').value
                    if query.lower() in x['name'].lower()]
        internchannels = [{
            'icon': x['name'].lower(),
            'name': x['name'],
            'url': x['url'],
        } for x in Config('SOCIAL.INTERNAL_COMMUNICATION_PLATFORMS').value
                          if query.lower() in x['name'].lower()]

        meeting_notes = MeetingNote.objects.filter(
            Q(text_date__icontains=query) | Q(text_keywords__icontains=query)
        ).past().LIST__search_results()[:5]

        guildes = Guilde.objects.filter(
            Q(str_name_en_US__icontains=query)
            | Q(text_description_en_US__icontains=query)).LIST__search_results(
            )[:5]

        machines = Machine.objects.filter(
            Q(str_name_en_US__icontains=query)
            | Q(text_description_en_US__icontains=query)).LIST__search_results(
            )[:5]

        spaces = Space.objects.filter(
            Q(str_name_en_US__icontains=query)
            | Q(text_description_en_US__icontains=query)).LIST__search_results(
            )[:5]

        consensus_items = Consensus.objects.filter(
            Q(str_name_en_US__icontains=query)
            | Q(text_description_en_US__icontains=query)).LIST__search_results(
            )[:5]

        projects = Project.objects.filter(
            Q(str_name_en_US__icontains=query)
            | Q(text_description_en_US__icontains=query)).LIST__search_results(
            )[:5]

        # search in wiki
        try:
            wiki_search_results = MediaWiki().search(query)
        except:
            self.log('-> ERROR: wiki search failed')
            wiki_search_results = []

        # search in discourse
        try:
            discourse_search_results = Discourse().search(query)
        except:
            self.log('-> ERROR: discourse search failed')
            discourse_search_results = []

        return networks + internchannels + events + guildes + machines + spaces + meeting_notes + consensus_items + projects + wiki_search_results + discourse_search_results
示例#28
0
 def config(self):
     return Config('BASICS.WIKI').value
示例#29
0
    def JSON__overlapping_events(self, new_event_UNIX_time,
                                 new_event_duration_minutes, space):
        Log().print(
            'Event.objects.JSON__overlapping_events(self, new_event_UNIX_time={}, new_event_duration_minutes={}, space={})'
            .format(new_event_UNIX_time, new_event_duration_minutes, space))
        import pytz
        from datetime import datetime, timedelta
        from _setup.models import Config
        from _database.models import Event

        local_time = datetime.fromtimestamp(
            new_event_UNIX_time,
            pytz.timezone(Config('PHYSICAL_SPACE.TIMEZONE_STRING').value))

        hours_before = 1
        hours_event_duration = round(new_event_duration_minutes / 60)
        hours_after = 1

        times = []

        counter = 0
        while counter < hours_before:
            Log().print('while counter < hours_before')
            counter += 1
            times.insert(
                0, {
                    'int_UNIX_time':
                    round(new_event_UNIX_time - (counter * 60)),
                    'str_readable':
                    str((local_time +
                         timedelta(hours=-counter)).strftime('%I:%M %p'))
                })

        counter = 0
        while counter < hours_event_duration:
            Log().print('while counter < hours_event_duration')
            times.append({
                'int_UNIX_time':
                round(new_event_UNIX_time + (counter * 60)),
                'str_readable':
                str((local_time +
                     timedelta(hours=counter)).strftime('%I:%M %p'))
            })
            counter += 1

        while (counter - hours_event_duration) < hours_after:
            Log().print('while (counter-hours_event_duration) < hours_after:')
            times.append({
                'int_UNIX_time':
                round(new_event_UNIX_time + (counter * 60)),
                'str_readable':
                str((local_time +
                     timedelta(hours=counter)).strftime('%I:%M %p'))
            })
            counter += 1

        for time in times:
            time['int_percent_height'] = str(100 / len(times)) + '%'

        queryset_overlapping_events = Event.objects.QUERYSET__in_timeframe(
            new_event_UNIX_time,
            new_event_UNIX_time + (new_event_duration_minutes * 60), space)

        # get values needed to show events in correct position
        list_overlapping_events = []
        for event in queryset_overlapping_events:
            minutes_distance = (
                (event.int_UNIXtime_event_start - times[0]['int_UNIX_time']) /
                60) + 60

            list_overlapping_events.append({
                'str_name_en_US':
                event.str_name_en_US,
                'str_slug':
                event.str_slug,
                'int_percent_top_distance':
                str(round((minutes_distance / (len(times) * 60)) * 100)) + '%',
                'int_percent_height':
                str(round(event.int_minutes_duration /
                          (len(times) * 60) * 100)) + '%'
            })

        your_event_minutes_distance = (
            (new_event_UNIX_time - times[0]['int_UNIX_time']) / 60) + 60
        Log().print('--> return JSON ({} overlapping events)'.format(
            len(list_overlapping_events)))
        return {
            'times': times,
            'your_event': {
                'int_percent_top_distance':
                str(
                    round((your_event_minutes_distance /
                           (len(times) * 60)) * 100)) + '%',
                'int_percent_height':
                str(round(new_event_duration_minutes /
                          (len(times) * 60) * 100)) + '%'
            },
            'overlapping_events': list_overlapping_events
        }
示例#30
0
    def createEvent(self, event):
        Log().print('createEvent(event)')
        from _setup.models import Config
        from dateutil.parser import parse
        from datetime import datetime

        HACKERSPACE_NAME = Config('BASICS.NAME').value
        HACKERSPACE_ADDRESS = Config('PHYSICAL_SPACE.ADDRESS').value
        str_location_name = event['venue'][
            'name'] if 'venue' in event and event['venue']['name'] and event[
                'venue']['name'] != HACKERSPACE_NAME else HACKERSPACE_NAME
        str_location_street = event['venue'][
            'address_1'] if 'venue' in event and event['venue'][
                'name'] and event['venue'][
                    'name'] != HACKERSPACE_NAME else HACKERSPACE_ADDRESS[
                        'STREET']
        str_location_zip = event['venue'][
            'zip'] if 'venue' in event and 'zip' in event['venue'] and event[
                'venue']['name'] and event['venue'][
                    'name'] != HACKERSPACE_NAME else HACKERSPACE_ADDRESS['ZIP']
        str_location_city = event['venue'][
            'city'] if 'venue' in event and 'city' in event['venue'] and event[
                'venue']['name'] and event['venue'][
                    'name'] != HACKERSPACE_NAME else HACKERSPACE_ADDRESS['CITY']
        str_location_countrycode = event['venue']['country'].upper(
        ) if 'venue' in event and 'country' in event['venue'] and event[
            'venue']['name'] and event['venue'][
                'name'] != HACKERSPACE_NAME else HACKERSPACE_ADDRESS[
                    'COUNTRYCODE']

        Event().create(
            json_content={
                'str_name_en_US':
                event['name'] if 'name' in event else event['title'],
                'int_UNIXtime_event_start':
                round(event['time'] / 1000) if 'time' in
                event else parse(event['event']['start']).timestamp(),
                'int_UNIXtime_event_end':
                round(event['time'] / 1000) +
                (event['duration'] /
                 1000) if 'time' in event else parse(event['event']['end']).
                timestamp() if 'end' in event['event'] else
                parse(event['event']['start']).timestamp() + (120 * 60),
                'int_minutes_duration': ((event['duration'] / 1000) /
                                         60) if 'duration' in
                event else round((parse(event['event']['end']).timestamp() -
                                  parse(event['event']['start']).timestamp()) /
                                 1000) if 'end' in event['event'] else 120,
                'url_featured_photo':
                event['featured_photo']['photo_link'] if 'featured_photo' in
                event else event['image_url'] if 'image_url' in
                event and event['image_url'] else None,
                'text_description_en_US':
                event['description'],
                'str_location':
                str_location_name + '\n' + str_location_street + '\n' +
                str_location_zip + ', ' + str_location_city + ', ' +
                str_location_countrycode,
                'one_space':
                self.RESULT__extractSpace(event),
                'one_guilde':
                self.RESULT__extractGuilde(event),
                'str_series_id':
                event['series']['id'] if 'series' in event else None,
                'int_series_startUNIX':
                round(event['series']['start_date'] / 1000) if 'series' in
                event and 'start_date' in event['series'] else None,
                'int_series_endUNIX':
                round(event['series']['end_date'] / 1000) if 'series' in event
                and 'end_date' in event['series'] else None,
                'text_series_timing':
                'weekly: ' + str(event['series']['weekly']) if 'series' in
                event and 'weekly' in event['series'] else 'monthly: ' +
                str(event['series']['monthly']) if 'series' in
                event and 'monthly' in event['series'] else None,
                'url_meetup_event':
                event['link'] if 'link' in event else None,
                'int_UNIXtime_created':
                event['created'] if 'created' in
                event else parse(event['created_at']).timestamp(),
                'int_UNIXtime_updated':
                event['updated'] if 'updated' in
                event else parse(event['last_posted_at']).timestamp(),
                'str_timezone':
                self.STR__extractTimezone(event)
            })