def show_menu(self): Log().show_message( 'Welcome! How can I help you? (enter a number) '+self.options_string) selection_processed = False while selection_processed == False: try: selection = 1 if self.test else input() selector_number = int(selection)-1 if self.options[selector_number] == 'Create a new website': if self.test: break SetupNew() selection_processed = True elif self.options[selector_number] == 'Export current setup': SetupExport(self.backup_files) selection_processed = True elif self.options[selector_number] == 'Delete current setup': SetupDelete(self.backup_files) selection_processed = True elif self.options[selector_number] == 'Import backup': SetupImport(self.backup_files) selection_processed = True else: Log().show_message( 'ERROR: That option doesn\'t exist. How can I help you? (enter a number) '+self.options_string) except KeyboardInterrupt: break except (IndexError, ValueError): Log().show_message( 'ERROR: That option doesn\'t exist. How can I help you? (enter a number) '+self.options_string)
def __init__(self, backup_files, test=False): self.backup_files = backup_files self.test = test Log().show_messages([ 'Hello! It seems you want to export your current settings? (your config.json, secrets.json and important images)' ]) Log().show_message( 'If that\'s the case, enter now a name for the exported folder. (or press Enter to exit)') folder_name = 'unittest' if self.test else input() if not folder_name: Log().show_message('Ok, got it. Maybe another time.') exit() else: from zipfile import ZipFile, ZIP_DEFLATED # copy files into folder with ZipFile('setup_backup__'+folder_name+'.zip', 'w', ZIP_DEFLATED) as zip: # writing each file one by one for file in self.backup_files: try: zip.write(file) except: pass Log().show_message('✅Done! Exported "'+folder_name + '" ('+self.get_size('setup_backup__'+folder_name+'.zip')+')')
def str_relative_time(self): Log().print('photo.str_relative_time') import time from datetime import datetime timestamp = self.int_UNIXtime_created # in last 60 minutes if timestamp >= time.time() - (60 * 60): minutes_in_past = int((time.time() - timestamp) / 60) Log().print('--> return STR') return str(minutes_in_past) + ' minute' + ( 's' if minutes_in_past > 1 else '') + ' ago' # in last 24 hours elif timestamp >= time.time() - (60 * 60 * 24): hours_in_past = int(((time.time() - timestamp) / 60) / 60) Log().print('--> return STR') return str(hours_in_past) + ' hour' + ('s' if hours_in_past > 1 else '') + ' ago' # else if in last 6 days, return number of days ago elif timestamp >= time.time() - (60 * 60 * 24 * 6): days_in_past = int((((time.time() - timestamp) / 60) / 60) / 24) Log().print('--> return STR') return str(days_in_past) + ' day' + ('s' if days_in_past > 1 else '') + ' ago' # else date string else: Log().print('--> return STR') return datetime.utcfromtimestamp(timestamp).strftime('%b %d, %Y')
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()
def QUERYSET__in_timeframe(self, from_UNIX_time, to_UNIX_time, str_space_name=None): Log().print( 'Event.objects.QUERYSET__in_timeframe(self, from_UNIX_time={}, to_UNIX_time={}, str_space_name={})' .format(from_UNIX_time, to_UNIX_time, str_space_name)) from django.db.models import Q from _database.models import Space if str_space_name: space = Space.objects.QUERYSET__by_name(str_space_name) if space: self = self.filter(one_space=space) output = self.filter( # get events that start after from_UNIX_time and end before to_UNIX_time (Q(int_UNIXtime_event_start__gte=from_UNIX_time) & Q(int_UNIXtime_event_start__lte=to_UNIX_time)) # get events that end after from_UNIX_time and before to_UNIX_time | (Q(int_UNIXtime_event_end__gte=from_UNIX_time) & Q(int_UNIXtime_event_end__lte=to_UNIX_time)) # get events that start before from_UNIX_time and end after to_UNIX_time | (Q(int_UNIXtime_event_start__lte=from_UNIX_time) & Q(int_UNIXtime_event_end__gte=to_UNIX_time))).exclude( Q(int_UNIXtime_event_start__gte=to_UNIX_time) | Q(int_UNIXtime_event_end__lte=from_UNIX_time)).exclude( boolean_approved=False) Log().print('--> return QUERYSET ({} results)'.format(output.count())) return output
def setup(self): from pyprintplus import Log import json try: if not self.urls: Log().show_messages([ 'Let\'s setup Google Photos - to automatically import photos from Google Photos into your websites photo section.' ]) Log().show_message( 'Enter the URLs on Google Photos which we should scrape - for example an album: (separated by ,)' ) self.urls = SetupTestConfig( 'SOCIAL.GOOGLE_PHOTOS_ALBUM_URLS' ).value[0] if self.test else input() if not self.urls and not self.test: raise KeyboardInterrupt with open('_setup/config.json') as json_config: config = json.load(json_config) config['SOCIAL'][ 'GOOGLE_PHOTOS_ALBUM_URLS'] = self.urls.replace( ', ', ',').split(',') with open('_setup/config.json', 'w') as outfile: json.dump(config, outfile, indent=4) Log().show_message('Google Photos setup complete.') except KeyboardInterrupt: Log().show_message('Ok, canceled setup.')
def JSON_RESPONSE_more_photos(self, request): Log().print('JSON_RESPONSE_more_photos(request)') from django.http import JsonResponse from django.template.loader import get_template from _database.models import Photo start_from = int(request.GET.get('from', None)) upt_to = int(start_from + 30) # get photos: latest, oldest or random if request.GET.get('type', None) == 'latest': queryset = Photo.objects.latest() elif request.GET.get('type', None) == 'oldest': queryset = Photo.objects.oldest() elif request.GET.get('type', None) == 'random': queryset = Photo.objects.random() Log().print('--> return JsonResponse') return JsonResponse({ 'html': get_template('components/body/photos_list.html').render({ 'photos': queryset[start_from:upt_to] if request.GET.get('type', None) != 'random' else queryset, }), 'continue_from': upt_to, 'more_results': True if request.GET.get('type', None) == 'random' or queryset.count() > upt_to else False })
def JSON_RESPONSE_more_results(self, request, template_path, queryset): Log().print( 'JSON_RESPONSE_more_results(request, template_path, queryset)') from django.http import JsonResponse from django.template.loader import get_template # see if request comes from a guilde/space page, then show guilde/space events, not all events if request.GET.get('origin', None): if 'guilde/' in request.GET.get('origin', None): queryset = queryset.filter( one_guilde__str_slug=request.GET.get('origin', None)[1:]) elif 'space/' in request.GET.get('origin', None): queryset = queryset.filter( one_space__str_slug=request.GET.get('origin', None)[1:]) start_from = int(request.GET.get('from', None)) upt_to = int(start_from + 10) Log().print('--> return JsonResponse') return JsonResponse({ 'html': get_template('components/body/' + template_path).render({ 'all_results': queryset[start_from:upt_to], 'specific_selector': request.GET.get('specific_selector', None) }), 'continue_from': upt_to, 'more_results': True if queryset.count() > upt_to else False })
def __init__(self, config): self.config = config # save lat/lon based on address if self.config['PHYSICAL_SPACE']['ADDRESS']['STREET'] and self.config[ 'PHYSICAL_SPACE']['ADDRESS']['CITY']: Log().show_message( 'Ok, great! Give me a seconds, so I can try to find and save the matching LAT_LON and TIMEZONE_STRING as well...' ) location, lat, lon = self.get_lat_lon_and_location( self.config['PHYSICAL_SPACE']['ADDRESS']['STREET'] + ', ' + self.config['PHYSICAL_SPACE']['ADDRESS']['CITY'] + (', ' + self.config['PHYSICAL_SPACE']['ADDRESS']['STATE'] if self.config['PHYSICAL_SPACE']['ADDRESS']['STATE'] else '') + (', ' + self.config['PHYSICAL_SPACE']['ADDRESS']['COUNTRYCODE'] if self. config['PHYSICAL_SPACE']['ADDRESS']['COUNTRYCODE'] else '')) if lat != None: self.config['PHYSICAL_SPACE']['LAT_LON'] = [lat, lon] # also save timezone string based on lat/lon self.config['PHYSICAL_SPACE'][ 'TIMEZONE_STRING'] = self.STR__get_timezone_from_lat_lon( lat, lon) Log().show_message('It worked!')
def setup(self): import json try: if not self.url: Log().show_messages([ 'Let\'s setup Flickr - to automatically import photos from Flickr into your websites photo section.' ]) Log().show_message( 'Enter the URL on Flickr which we should scrape - for example an album:' ) self.url = None if self.test else input() if not self.url and not self.test: raise KeyboardInterrupt with open('_setup/config.json') as json_config: config = json.load(json_config) config['SOCIAL']['FLICKR_URL'] = self.url with open('_setup/config.json', 'w') as outfile: json.dump(config, outfile, indent=4) Log().show_message('Flickr setup complete.') except KeyboardInterrupt: Log().show_message('Ok, canceled setup.')
def setup(self): import json try: if not self.url: # try to find the url based on the website domain domain = Config('WEBSITE.DOMAIN').value if domain and requests.get('https://' + domain + '/api.php').status_code == 200: self.url = 'https://' + domain + '/api.php' else: Log().show_messages( ['Let\'s add your hackspaces Wiki to the search!']) Log().show_message('What is the API URL of your Wiki?') self.url = SetupTestConfig( 'BASICS.WIKI.API_URL').value if self.test else input() while not self.url: self.url = input() with open('_setup/config.json') as json_config: config = json.load(json_config) config['BASICS']['WIKI']['API_URL'] = self.url with open('_setup/config.json', 'w') as outfile: json.dump(config, outfile, indent=4) Log().show_message('MediaWiki setup complete.') except KeyboardInterrupt: Log().show_message('Ok, canceled setup.')
def LIST__in_minutes(self, minutes, name_only=False): Log().print( 'Event.objects.LIST__in_minutes(self,minutes={},name_only={})'. format(minutes, name_only)) import pytz from datetime import datetime, timedelta from _setup.models import Config date_in_x_minutes = datetime.now( pytz.timezone( Config('PHYSICAL_SPACE.TIMEZONE_STRING').value)) + timedelta( minutes=minutes) events_in_x_minutes = [] self = self.QUERYSET__upcoming()[:3] for event in self.all(): event_start_date = event.datetime_start if event_start_date.date() == date_in_x_minutes.date() \ and event_start_date.hour == date_in_x_minutes.hour \ and event_start_date.minute == date_in_x_minutes.minute: events_in_x_minutes.append(event) if name_only == True: Log().print('--> return LIST') return [ x.str_name_en_US.replace('&', 'and').replace('@', 'at').replace( '|', '').replace('#', 'sharp') for x in events_in_x_minutes ] Log().print('--> return LIST') return events_in_x_minutes
def QUERYSET__next_meeting(self): Log().print('Event.objects.QUERYSET__next_meeting(self)') import time Log().print('--> return QUERYSET') return self.filter(str_name_en_US__icontains='General Meeting', int_UNIXtime_event_start__gt=time.time()).order_by( 'int_UNIXtime_event_start').first()
def __init__(self, group, test): self.group = group self.test = test try: if not self.group: ask_input = False space_name = Config('BASICS.NAME').value if requests.get('https://www.meetup.com/' + space_name.lower()).status_code == 200: Log().show_message( 'Is this your hackpace meetup group? (Y/N): https://www.meetup.com/' + space_name.lower()) reply = input() if reply.lower() == 'y': self.group = 'https://www.meetup.com/' + space_name.lower( ) else: ask_input = True else: ask_input = True if ask_input: Log().show_messages([ 'Let\'s setup Meetup.com - so we can automatically import all your events from Meetup and show them on your new website.' ]) Log().show_message('What is the URL of your Meetup group?') self.group = SetupTestConfig( 'EVENTS.MEETUP_GROUP').value if self.test else input() if not self.group and not self.test: raise KeyboardInterrupt with open('_setup/config.json') as json_config: config = json.load(json_config) if self.group.endswith('/'): self.group = self.group[:-1] config['EVENTS']['MEETUP_GROUP'] = self.group.split( '/')[-1] for entry in config['SOCIAL']['SOCIAL_NETWORKS']: if 'meetup.com/' in entry['url']: break else: config['SOCIAL']['SOCIAL_NETWORKS'].append({ "name": "Meetup", "url": self.group }) with open('_setup/config.json', 'w') as outfile: json.dump(config, outfile, indent=4) Log().show_message('Meetup setup complete.') except KeyboardInterrupt: Log().show_message('Ok, canceled setup.')
def QUERYSET__now(self): Log().print('Event.objects.QUERYSET__now(self)') import time Log().print('--> return QUERYSET') return self.filter( int_UNIXtime_event_end__gt=time.time(), int_UNIXtime_event_start__lte=time.time(), boolean_approved=True).order_by('int_UNIXtime_event_start')
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 QUERYSET__upcoming(self, boolean_approved=False): Log().print( 'Event.objects.QUERYSET__upcoming(self,boolean_approved={})'. format(boolean_approved)) import time Log().print('--> return QUERYSET') return self.filter(int_UNIXtime_event_end__gt=time.time()).exclude( boolean_approved=boolean_approved).order_by( 'int_UNIXtime_event_start')
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 import_from_discourse(self): print('import_from_discourse()') from _database.models import Person from _apis.models import Discourse from dateutil import parser from _setup.models import Secret import time import requests from pyprintplus import Log DISCOURSE_URL = Secret('DISCOURSE.DISCOURSE_URL').value if DISCOURSE_URL: Log().show_message( '✅ Found DISCOURSE.DISCOURSE_URL - start importing Consensus Items from Discourse.' ) time.sleep(2) if requests.get(DISCOURSE_URL + '/c/consensus-items').status_code == 200: consensus_items = Discourse().get_category_posts( category='consensus-items', all_pages=True) print('process {} consensus-items'.format( len(consensus_items))) for consensus_item in consensus_items: if consensus_item[ 'title'] != 'About the Consensus Items category': Consensus().create( json_content={ 'str_name_en_US': consensus_item['title'], 'url_discourse': Secret('DISCOURSE.DISCOURSE_URL').value + 't/' + consensus_item['slug'], 'text_description_en_US': consensus_item['excerpt'], 'int_UNIXtime_created': round( datetime.timestamp( parser.parse( consensus_item['created_at']))), 'one_creator': Person.objects.get_discourse_creator( consensus_item['slug']), }) else: Log().show_message( 'WARNING: Can\'t find the "consensus-items" category on your Discourse. Skipped importing Consensus Items from Discourse.' ) time.sleep(4) else: Log().show_message( 'WARNING: Can\'t find the DISCOURSE.DISCOURSE_URL in your secrets.json. Will skip Discourse for now.' ) time.sleep(4)
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 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 check_mode_testing(self): return True # 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 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 QUERYSET__in_space(self, one_space=None, str_space=None): Log().print( 'Event.objects.QUERYSET__in_space(self, one_space={}, str_space={})' .format(one_space, str_space)) if one_space: Log().print('--> return QUERYSET') return self.filter(one_space=one_space) elif str_space: Log().print('--> return QUERYSET') return self.filter(one_space__str_name_en_US=str_space) else: return []
def QUERYSET__by_guilde(self, one_guilde=None, str_guilde=None): Log().print( 'Event.objects.QUERYSET__by_guilde(self, one_guilde={}, str_guilde={})' .format(one_guilde, str_guilde)) if one_guilde: Log().print('--> return QUERYSET') return self.filter(one_guilde=one_guilde) elif str_guilde: Log().print('--> return QUERYSET') return self.filter(one_guilde__str_name_en_US__contains=str_guilde) else: return []
def QUERYSET__by_host(self, one_host=None, str_host=None): Log().print( 'Event.objects.QUERYSET__by_host(self, one_host={}, str_host={})'. format(one_host, str_host)) if one_host: Log().print('--> return QUERYSET') return self.filter(many_hosts=one_host) elif str_host: Log().print('--> return QUERYSET') return self.filter(many_hosts__str_name_en_US__contains=str_host) else: return []
def setup(self): import json try: if not self.username or not self.hashtag: Log().show_messages([ 'Let\'s setup Instagram - to automatically import photos from Instagram into your websites photo section.' ]) if not self.username: Log().show_message( 'What is the username of your hackspace on Instagram?') self.username = SetupTestConfig( 'SOCIAL.INSTAGRAM_USERNAME' ).value if self.test else input() if self.username and 'instagram.com/' in self.username: self.username = self.username.split( 'instagram.com/')[1].replace('/', '') if not self.hashtag: Log().show_message( 'What hashtag does your hackspace use on Instagram (and Twitter)?' ) self.hashtag = SetupTestConfig( 'SOCIAL.HASHTAG').value if self.test else input( ).replace('#', '') with open('_setup/config.json') as json_config: config = json.load(json_config) if self.username: for entry in config['SOCIAL']['SOCIAL_NETWORKS']: if 'instagram.com/' in entry['url']: break else: if self.username: config['SOCIAL']['SOCIAL_NETWORKS'].append({ "name": "Instagram", "url": "https://www.instagram.com/" + self.username + '/' }) config['SOCIAL']['HASHTAG'] = self.hashtag with open('_setup/config.json', 'w') as outfile: json.dump(config, outfile, indent=4) Log().show_message('Instagram setup complete.') except KeyboardInterrupt: Log().show_message('Ok, canceled setup.')
def setup(self): from pyprintplus import Log import json try: if not self.access_key_id or not self.secret_access_key or not self.bucket_name: Log().show_messages( ['Let\'s setup AWS - so whenever a user creates a new event via your new website, the event image will be uploaded to AWS S3.']) Log().show_message( 'To upload photos to S3: Enter your AWS ACCESS_KEYID') self.access_key_id = None if self.test else input() if not self.access_key_id and not self.test: raise KeyboardInterrupt Log().show_message( 'To upload photos to S3: Enter your AWS SECRET_ACCESS_KEY') self.secret_access_key = None if self.test else input() if not self.secret_access_key and not self.test: raise KeyboardInterrupt Log().show_message( 'To upload photos to S3: Enter your S3 BUCKET_NAME') self.bucket_name = None if self.test else input() if not self.bucket_name and not self.test: raise KeyboardInterrupt Log().show_message( 'To upload photos to S3: Enter your S3 SERVER_AREA') self.server_area = None if self.test else input() if not self.server_area and not self.test: raise KeyboardInterrupt Log().show_message( 'To delete photos from S3: Did you configure the AWS CLI? (yes|no)') reply = 'yes' if self.test else input() if reply == 'no': Log().show_messages([ 'Install the AWS CLI: https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html', 'Configure your AWS CLI: https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html#cli-quick-configuration' ]) with open('_setup/secrets.json') as json_config: secrets = json.load(json_config) secrets['AWS']['ACCESS_KEYID'] = self.access_key_id secrets['AWS']['SECRET_ACCESS_KEY'] = self.secret_access_key secrets['AWS']['S3']['BUCKET_NAME'] = self.bucket_name secrets['AWS']['S3']['SERVER_AREA'] = self.server_area with open('_setup/secrets.json', 'w') as outfile: json.dump(secrets, outfile, indent=4) Log().show_message('Aws setup complete.') except KeyboardInterrupt: Log().show_message('Ok, canceled setup.')
def handle(self, *args, **options): from _database.models import Event, Space, Consensus, Person, Wish, Photo, Project from _setup.models import Config from _setup.models import Secret from pyprintplus import Log import time import requests Log().show_message( 'I will now start to update your database, based on your secrets.json and config.json. Depending on your settings, amount of events & photos & Discourse entries from your this can take everything from seconds to hours (?). But you can already test your website - by opening a new terminal window and run "python manage.py runserver 0.0.0.0:8000" - and open 0.0.0.0:8000 in your web browser.' ) time.sleep(5) # create default space for events if not Space.objects.filter(str_name_en_US=Config( 'EVENTS.EVENTS_SPACE_DEFAULT').value).exists(): Space( str_name_en_US=Config('EVENTS.EVENTS_SPACE_DEFAULT').value, text_description_en_US= 'Work on cool projects in our largest community area - the {}!' .format(Config('EVENTS.EVENTS_SPACE_DEFAULT').value)).save() # import data from Discourse Person.objects.import_from_discourse() Consensus.objects.import_from_discourse() Project.objects.import_from_discourse() # import events from Meetup Event.objects.import_from_meetup() extra_groups = Config('EVENTS.EXTRA_MEETUP_GROUPS').value if extra_groups: Log().show_message( 'Import events from additional Meetup groups ...') time.sleep(2) for group in extra_groups: Event.objects.import_from_meetup(group) # import photos Log().show_message( 'Start importing your existing photos from the web ...') time.sleep(2) Photo.objects.import_from_google_photos() Photo.objects.import_from_twitter() Photo.objects.import_from_wiki() Photo.objects.import_from_instagram() Photo.objects.import_from_flickr() Log().show_message('✅ Done! I updated the database') time.sleep(2)