def generate_ical_for_job(job): # Used https://icalendar.org/validator.html to validate output # Gmail will not update or cancel the existing event, but add a new one if the method is PUBLISH, # However, using REQUEST as the method would cause more confusion as it would look to the members as if they could # actually cancel their participation, be declining the event. # Thunderbird recognizes the changes correctly # On Android Gmail will show the same behaviour as on the desktop when using the event widget. Opening the attached # ics with a Calender App (e.g. Google Calendar) yields the correct behaviour (existing event is overwritten). # Using a non Gmail account in the Gmail app seems to break the ics file, for some reason. # K9-Mail shows the attachment and opening it in a calendar app works fine. # Outlook and Microsoft Mail do not show the event nicely, however the ics attachment can be opened and added to # calendar. # Not tested yet: Apples c = Calendar() c.extra.append( ContentLine(name="METHOD", value="CANCEL" if job.canceled else "PUBLISH")) e = Event() # By giving it a UID the calendar will (hopefully) replace previous versions of this event. e.uid = f'{repr(job)}@{Config.server_url()}' # DTSTAMP is required: https://tools.ietf.org/html/rfc5545#section-3.6.1 e.extra.append( ContentLine(name="DTSTAMP", value=timezone.now().astimezone( timezone.utc).strftime('%Y%m%dT%H%M%SZ'))) e.name = Config.organisation_name() + ' ' + _( 'Einsatz') + ': ' + job.type.get_name e.location = job.type.location e.description = job.type.description # Using FORM 2: https://tools.ietf.org/html/rfc5545#section-3.3.5 e.begin = job.start_time() e.duration = {'hours': job.duration} e.extra.append( ContentLine(name=f"ORGANIZER;CN={Config.organisation_name()}", value=f"mailto:{job.type.activityarea.get_email()}")) if job.canceled: e.status = 'CANCELLED' c.events.add(e) content = re.sub(r"\r?\n", "\r\n", str(c)) # Fold lines https://tools.ietf.org/html/rfc5545#section-3.1 content = re.sub("(.{74})", "\\1\r\n ", content) # fold at 74 such that the whitespace fits return ical("{}.ics".format(_('Einsatz')), content)
async def main(): s = spond.Spond(username=username, password=password) c = Calendar() c.method = 'PUBLISH' events = await s.getEvents() for event in events: e = Event() e.uid = event['id'] e.name = event['heading'] e.description = event['description'] e.begin = event['startTimestamp'] e.end = event['endTimestamp'] e.sequence = event['updated'] if 'cancelled' in event and event['cancelled']: e.status = 'Cancelled' if 'location' in event: e.location = "{}, {}".format(event['location']['feature'], event['location']['address']) c.events.add(e) with open(ics_file, 'w') as out_file: out_file.writelines(c) await s.clientsession.close()
def index(request): code = request.GET.get('code') step_3 = 'https://foursquare.com/oauth2/access_token?client_id=%s&client_secret=%s&grant_type=authorization_code&redirect_uri=%s&code=%s' % ( YOUR_CLIENT_ID, YOUR_CLIENT_SECRET, YOUR_REGISTERED_REDIRECT_URI, code) resp = requests.get(url=step_3) token = json.loads(resp.content) nowTime = datetime.datetime.now().strftime('%Y%m%d') #现在 # 今天日期 today = datetime.date.today() # 昨天时间 yesterday = today - datetime.timedelta(days=1) # 明天时间 tomorrow = today + datetime.timedelta(days=1) #yesterday_start_time = int(time.mktime(time.strptime(str(yesterday), '%Y-%m-%d'))) # 2009-06-01 00:00:00 yesterday_start_time = 1243785600 today_end_time = (int(time.mktime(time.strptime(str(tomorrow), '%Y-%m-%d')))) offset = 0 c = Calendar() while True: url = 'https://api.foursquare.com/v2/users/self/checkins?oauth_token=%s&v=%s&beforeTimestamp=%s&afterTimestamp=%s&limit=250&&offset=%s' % ( token['access_token'], nowTime, today_end_time, yesterday_start_time, offset) resp = requests.get(url=url) data = json.loads(resp.text) if len(data['response']['checkins']['items']) == 0: break for item in data['response']['checkins']['items']: try: e = Event() e.name = item['venue']['name'] e.uid = item['id'] e.begin = item['createdAt'] + item['timeZoneOffset'] e.location = '%s' % '-'.join( [s for s in item['venue']['location']['formattedAddress']]) e.status = 'CONFIRMED' c.events.add(e) print(item['venue']['location']['formattedAddress']) except: continue offset += 250 file_path = os.path.join(settings.MEDIA_ROOT, 'HistoryCheckins', 'HistoryCheckins.ics') [dir_name, file_name] = os.path.split(file_path) if not os.path.exists(dir_name): os.makedirs(dir_name) with open(file_path, 'w', encoding='utf-8') as f: f.writelines(c) return HttpResponse(json.dumps({"success": True}))