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()
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)
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)
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 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
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
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 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')
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) }
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
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 __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
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
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('<br>', '<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)
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'
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)
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})
def config(self): return {"FLICKR_URL": Config('SOCIAL.FLICKR_URL').value}
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!')
def config(self): return { "GOOGLE_PHOTOS_ALBUM_URLS": Config('SOCIAL.GOOGLE_PHOTOS_ALBUM_URLS').value }
def config(self): return {"username": Config('SOCIAL.SOCIAL_NETWORKS', username_for='twitter.com').value, "hashtag": Config('SOCIAL.HASHTAG').value}
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
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('<br>', '<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)
def config(self): return {"group": Config('EVENTS.MEETUP_GROUP').value}
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()))
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)
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
def config(self): return Config('BASICS.WIKI').value
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 }
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) })