def create(addr: str) -> requests.Response: """Add a subscription email address.""" return requests.post( f"https://api.mailgun.net/v3/lists/{mailing_list()}/members", auth=("api", get_secret("MG_API_KEY")), data={"upsert": True, "subscribed": True, "address": addr}, )
def get_file_for_date(full_date: datetime) -> Optional[str]: """Determine if an archive file for a date exists.""" date_iso = helpers.format_datetime_ymd(full_date) save_dir = Path(get_secret("DOWNLOADS_DIR")).resolve() file_name = f"{FILE_NAME_BASE}{date_iso}{FILE_NAME_EXT}" full_path = save_dir / file_name # If the file exists, return a Path to it if full_path.exists(): return file_name return None
def validate(addr: str) -> bool: """Validate an email address using the Mailgun Email Validation API.""" # Assume the address is valid if we can't send out emails if not get_config("ENABLE_EMAIL_SENDING"): return True r = requests.get( "https://api.mailgun.net/v4/address/validate", auth=("api", get_secret("MG_API_KEY")), params={"address": addr}, ).json() # The address can be added if it's marked as deliverable return r["result"] == "deliverable"
def send(email: Dict[str, str]) -> bool: """Send out a completed email.""" # If email sending is not configured, just pretend the email # sent out correctly instead of making the caller handle the special case if not current_app.config["ENABLE_EMAIL_SENDING"]: return True # Attempt to send out the email r = requests.post( f'https://api.mailgun.net/v3/{get_secret("MG_DOMAIN")}/messages', auth=("api", get_secret("MG_API_KEY")), data=email, ) r.raise_for_status() return True
def download(prompt_id: str, url: str) -> dict[str, str]: """Download a Tweet's media.""" # Generate a random file name for the download original_f_name = original_name(url) temp_f_name = "{name}{ext}".format(name=secrets.token_hex(12), ext=PurePath(original_f_name).suffix) # Download the media to a temp directory r = requests.get(url) dl_path = Path(get_secret("IMAGES_DIR_TEMP")).resolve() / temp_f_name dl_path.write_bytes(r.content) # Return the original and temp file name return { "original": original_f_name, "temp": temp_f_name, "final": saved_name(prompt_id, url), }
def make() -> bool: """Generate a new Prompt archive spreadsheet.""" # Check that we have permission to write to the save directory save_dir = Path(get_secret("DOWNLOADS_DIR")).resolve() try: temp_file = save_dir / "perm.temp" temp_file.write_text("") temp_file.unlink() except PermissionError: return False # Set up all date values we need archive_years = database.prompt.get_years() archive_range = prompt_date_range() oldest_date = helpers.format_datetime_pretty(archive_range["oldest"]) newest_date = helpers.format_datetime_pretty(archive_range["newest"]) today = datetime.now() today_iso = helpers.format_datetime_ymd(today) today_pretty = helpers.format_datetime_pretty(today) # Put together the archive's file name file_name = f"{FILE_NAME_BASE}{today_iso}{FILE_NAME_EXT}" full_save_path = save_dir / file_name # Create a new spreadsheet file workbook_config = { "constant_memory": True, "default_date_format": "yyyy-mm-dd" } with xlsxwriter.Workbook(full_save_path, workbook_config) as workbook: # Create a bold text formatter bolded_text = workbook.add_format() bolded_text.set_bold() # Start by creating a page with basic file generation info worksheet = workbook.add_worksheet("Info") worksheet.write( 0, 0, f"#vss365 prompt archive from {oldest_date} to {newest_date}", ) worksheet.write(1, 0, "Sorted by prompt in alphabetical order") worksheet.write(2, 0, f"Generated on {today_pretty}") worksheet.write_url(3, 0, "https://vss365today.com") # Group each year's prompts in their own sheet for year in archive_years: worksheet = workbook.add_worksheet(str(year)) # Set the column widths widths = get_column_widths(int(year)) worksheet.set_column(0, 0, 10) worksheet.set_column(1, 1, widths.longest_word) worksheet.set_column(2, 2, widths.longest_handle) worksheet.set_column(3, 3, widths.longest_url) # Write the headings worksheet.write(0, 0, "Date", bolded_text) worksheet.write(0, 1, "Prompt", bolded_text) worksheet.write(0, 2, "Host", bolded_text) worksheet.write(0, 3, "URL", bolded_text) # Get the prompt archive for the current year for row, prompt in enumerate(get(int(year))): # Rows are zero-indexed, meaning we need to increment # so we don't clobber the headings row += 1 # Write all the data worksheet.write_datetime(row, 0, prompt.date) worksheet.write(row, 1, prompt.word) worksheet.write(row, 2, prompt.writer_handle) url = Prompt.make_url(prompt.writer_handle, prompt.tweet_id) worksheet.write_url(row, 3, url) return True
def move(details: dict) -> bool: """Move a media file from the temporary directory to final location.""" current_path = Path(get_secret("IMAGES_DIR_TEMP")) / details["temp"] final_path = Path(get_secret("IMAGES_DIR")) / details["final"] current_path.replace(final_path) return final_path.is_file()
def delete(prompt_id: str) -> bool: """Delete a media file.""" f_name = sorted(Path(get_secret("IMAGES_DIR")).glob(f"{prompt_id}*")) if len(f_name) == 1: f_name[0].unlink() return True
def delete(addr: str) -> requests.Response: """Remove a subscription email address.""" return requests.delete( f"https://api.mailgun.net/v3/lists/{mailing_list()}/members/{addr}", auth=("api", get_secret("MG_API_KEY")), )
def twitter_v2_api() -> tweepy.Client: """Connect to Twitter API v2 using a Bearer token.""" return tweepy.Client(bearer_token=get_secret("TWITTER_BEARER"))