completely revampted .env.template syntax, shiny new checker, better formatting and more

remotes/origin/CordlessCoder-envchecker
CordlessCoder 2 years ago
parent b2b4a08741
commit 629b74c5d4

@ -1,24 +1,40 @@
REDDIT_CLIENT_ID="" REDDIT_CLIENT_ID=""
#EXPLANATION the ID of your Reddit app of SCRIPT type #EXPLANATION the ID of your Reddit app of SCRIPT type
#RANGE 12:30
#MATCH_REGEX [-a-zA-Z0-9._~+/]+=*$
#OOB_ERROR The ID should be over 12 and under 30 characters, double check your input.
REDDIT_CLIENT_SECRET="" REDDIT_CLIENT_SECRET=""
#EXPLANATION the SECRET of your Reddit app of SCRIPT type #EXPLANATION the SECRET of your Reddit app of SCRIPT type
#RANGE 20:40
#MATCH_REGEX [-a-zA-Z0-9._~+/]+=*$
#OOB_ERROR The secret should be over 20 and under 40 characters, double check your input.
REDDIT_USERNAME="" REDDIT_USERNAME=""
#EXPLANATION the username of your reddit account #EXPLANATION the username of your reddit account
#RANGE 3:20
#MATCH_REGEX [_0-9a-zA-Z]+$
#OOB_ERROR A username HAS to be between 3 and 20 characters
REDDIT_PASSWORD="" REDDIT_PASSWORD=""
#EXPLANATION the password of your reddit account #EXPLANATION the password of your reddit account
#RANGE 8:None
#OOB_ERROR Password too short
#OPTIONAL #OPTIONAL
RANDOM_THREAD="no" RANDOM_THREAD="no"
#EXPLANATION If set to no, it will ask you a thread link to extract the thread, if yes it will randomize it. Default: "no" # If set to no, it will ask you a thread link to extract the thread, if yes it will randomize it. Default: "no"
REDDIT_2FA="" REDDIT_2FA=""
#MATCH_REGEX ^(yes|no) #MATCH_REGEX ^(yes|no)
#EXPLANATION Whether you have Reddit 2FA enabled, Valid options are "yes" and "no" #EXPLANATION Whether you have Reddit 2FA enabled, Valid options are "yes" and "no"
SUBREDDIT="AskReddit" SUBREDDIT="AskReddit"
#EXPLANATION what subreddit to pull posts from, the name of the sub, not the URL
#RANGE 3:20
#MATCH_REGEX [_0-9a-zA-Z]+$
#OOB_ERROR A subreddit name HAS to be between 3 and 20 characters
ALLOW_NSFW="False" ALLOW_NSFW="False"
#EXPLANATION Whether to allow NSFW content, True or False #EXPLANATION Whether to allow NSFW content, True or False
#MATCH_REGEX ^(True|False)$ #MATCH_REGEX ^(True|False)$
@ -29,16 +45,22 @@ POST_ID=""
THEME="LIGHT" THEME="LIGHT"
#EXPLANATION sets the Reddit theme, either LIGHT or DARK #EXPLANATION sets the Reddit theme, either LIGHT or DARK
#MATCH_REGEX ^(dark|light|DARK|LIGHT)$
TIMES_TO_RUN="" TIMES_TO_RUN=""
#EXPLANATION used if you want to run multiple times. set to an int e.g. 4 or 29 and leave blank for 1 #EXPLANATION used if you want to run multiple times. set to an int e.g. 4 or 29 and leave blank for 1
MAX_COMMENT_LENGTH="500" MAX_COMMENT_LENGTH="500"
#EXPLANATION max number of characters a comment can have. default is 500 #EXPLANATION max number of characters a comment can have. default is 500
#RANGE 0:10000
#MATCH_TYPE int
#OOB_ERROR the max comment length should be between 0 and 10000
#OPTIONAL
OPACITY="1" OPACITY="1"
#EXPLANATION sets the opacity of the comments, Range is 0 -> 1 recommended around 0.8-0.9 #EXPLANATION Sets the opacity of the comments when overlayed over the background
#RANGE 0:1
#MATCH_TYPE float
#OOB_ERROR The opacity HAS to be between 0 and 1
# see different voice options: todo: add docs # see different voice options: todo: add docs
VOICE="Matthew" VOICE="Matthew"
@ -49,4 +71,4 @@ TTsChoice="polly"
#OPTIONAL #OPTIONAL
STORYMODE="False" STORYMODE="False"
#EXPLANATION IN-PROGRESS - not yet implemented # IN-PROGRESS - not yet implemented

@ -1,3 +1,4 @@
# For most projects, this workflow file will not need changing; you simply need # For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository. # to commit it to your repository.
# #
@ -12,61 +13,61 @@
name: "CodeQL" name: "CodeQL"
on: on:
push: push:
branches: [ "master" ] branches: [ "master" ]
pull_request: pull_request:
# The branches below must be a subset of the branches above # The branches below must be a subset of the branches above
branches: [ "master" ] branches: [ "master" ]
schedule: schedule:
- cron: '16 14 * * 3' - cron: '16 14 * * 3'
jobs: jobs:
analyze: analyze:
name: Analyze name: Analyze
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
actions: read actions: read
contents: read contents: read
security-events: write security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
strategy: # Initializes the CodeQL tools for scanning.
fail-fast: false - name: Initialize CodeQL
matrix: uses: github/codeql-action/init@v2
language: [ 'python' ] with:
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] languages: ${{ matrix.language }}
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support # If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
steps: # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
- name: Checkout repository # queries: security-extended,security-and-quality
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below)
# If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild
- name: Autobuild uses: github/codeql-action/autobuild@v2
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell. # Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines. # If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: | # - run: |
# echo "Run, Build Application using script" # echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh # ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2 uses: github/codeql-action/analyze@v2

@ -1,5 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python
import time
from subprocess import Popen from subprocess import Popen
from dotenv import load_dotenv from dotenv import load_dotenv
@ -26,23 +25,16 @@ print(
""" """
) )
load_dotenv()
# Modified by JasonLovesDoggo # Modified by JasonLovesDoggo
print_markdown( print_markdown(
"### Thanks for using this tool! [Feel free to contribute to this project on GitHub!](https://lewismenelaws.com) If you have any questions, feel free to reach out to me on Twitter or submit a GitHub issue. You can find solutions to many common problems in the [Documentation](https://luka-hietala.gitbook.io/documentation-for-the-reddit-bot/)" "### Thanks for using this tool! [Feel free to contribute to this project on GitHub!](https://lewismenelaws.com) If you have any questions, feel free to reach out to me on Twitter or submit a GitHub issue. You can find solutions to many common problems in the [Documentation](https://luka-hietala.gitbook.io/documentation-for-the-reddit-bot/)"
) )
client_id = getenv("REDDIT_CLIENT_ID")
client_secret = getenv("REDDIT_CLIENT_SECRET")
username = getenv("REDDIT_USERNAME")
password = getenv("REDDIT_PASSWORD")
reddit2fa = getenv("REDDIT_2FA")
def main(): def main():
if check_env() is not True: if check_env() is not True:
exit() exit()
load_dotenv()
cleanup() cleanup()
def get_obj(): def get_obj():
@ -58,8 +50,7 @@ def main():
def run_many(times): def run_many(times):
for x in range(times): for x in range(1, times + 1):
x = x + 1
print_step( print_step(
f'on the {x}{("st" if x == 1 else ("nd" if x == 2 else ("rd" if x == 3 else "th")))} iteration of {times}' f'on the {x}{("st" if x == 1 else ("nd" if x == 2 else ("rd" if x == 3 else "th")))} iteration of {times}'
) # correct 1st 2nd 3rd 4th 5th.... ) # correct 1st 2nd 3rd 4th 5th....

@ -1,75 +1,184 @@
#!/usr/bin/env python #!/usr/bin/env python
import os import os
from rich.console import Console from rich.console import Console
from rich.table import Table
from rich import box
import re import re
import dotenv import dotenv
from utils.console import handle_input from utils.console import handle_input
console = Console() console = Console()
success = True
def check_env() -> bool: def check_env() -> bool:
if not os.path.exists(".env.template"): if not os.path.exists(".env.template"):
console.print("[red]Couldn't find .env.template. Unable to check variables.") console.print("[red]Couldn't find .env.template. Unable to check variables.")
return False return True
if not os.path.exists(".env"):
console.print("[red]Couldn't find the .env file, creating one now.")
with open(".env", "x") as file:
file.write("")
with open(".env.template", "r") as template: with open(".env.template", "r") as template:
# req_envs = [env.split("=")[0] for env in template.readlines() if "=" in env] # req_envs = [env.split("=")[0] for env in template.readlines() if "=" in env]
matching = {} matching = {}
explanations = {} explanations = {}
bounds = {}
types = {}
oob_errors = {}
req_envs = [] req_envs = []
var_optional = False var_optional = False
for line in template.readlines(): for line in template.readlines():
if "=" in line and var_optional is not True: if line.startswith("#") is not True and "=" in line and var_optional is not True:
req_envs.append(line.split("=")[0]) req_envs.append(line.split("=")[0])
elif "#OPTIONAL" in line: elif "#OPTIONAL" in line:
var_optional = True var_optional = True
elif line.startswith("#MATCH_REGEX "): elif line.startswith("#MATCH_REGEX "):
matching[req_envs[-1]] = line.removeprefix("#MATCH_REGEX ")[:-1] matching[req_envs[-1]] = line.removeprefix("#MATCH_REGEX ")[:-1]
var_optional = False var_optional = False
elif line.startswith("#OOB_ERROR "):
oob_errors[req_envs[-1]] = line.removeprefix("#OOB_ERROR ")[:-1]
var_optional = False
elif line.startswith("#RANGE "):
bounds[req_envs[-1]] = tuple(
map(
lambda x: float(x) if x != "None" else None,
line.removeprefix("#RANGE ")[:-1].split(":"),
)
)
var_optional = False
elif line.startswith("#MATCH_TYPE "):
types[req_envs[-1]] = eval(line.removeprefix("#MATCH_TYPE ")[:-1].split()[0])
var_optional = False
elif line.startswith("#EXPLANATION "): elif line.startswith("#EXPLANATION "):
explanations[req_envs[-1]] = line.removeprefix("#EXPLANATION ")[:-1] explanations[req_envs[-1]] = line.removeprefix("#EXPLANATION ")[:-1]
var_optional = False var_optional = False
else: else:
var_optional = False var_optional = False
missing = [] missing = set()
incorrect = [] incorrect = set()
dotenv.load_dotenv() dotenv.load_dotenv()
for env in req_envs: for env in req_envs:
value = os.getenv(env) value = os.getenv(env)
if value is None: if value is None:
missing.append(env) missing.add(env)
continue continue
if env in matching.keys(): if env in matching.keys():
env, re.match(matching[env], value) is None and incorrect.append(env) re.match(matching[env], value) is None and incorrect.add(env)
if len(missing): if env in bounds.keys() and env not in types.keys():
for i in range(len(missing)): len(value) >= bounds[env][0] or (
len(bounds[env]) > 1 and bounds[env][1] >= len(value)
) or incorrect.add(env)
continue
if env in types.keys():
try: try:
missing[i] = missing[i] + ": " + explanations[missing[i]] temp = types[env](value)
except KeyError: if env in bounds.keys():
pass (bounds[env][0] <= temp or incorrect.add(env)) and len(bounds[env]) > 1 and (
console.print( bounds[env][1] >= temp or incorrect.add(env)
f"[red]{'These variables are'*(len(missing) > 1) or 'This variable is'} non-optional and missing: \n\n" )
+ "\n\n".join(missing) except ValueError:
incorrect.add(env)
if len(missing):
table = Table(
title="Missing variables",
highlight=True,
show_lines=True,
box=box.ROUNDED,
border_style="#414868",
header_style="#C0CAF5 bold",
title_justify="left",
title_style="#C0CAF5 bold",
) )
table.add_column("Variable", justify="left", style="#7AA2F7 bold", no_wrap=True)
table.add_column("Explanation", justify="left", style="#BB9AF7", no_wrap=False)
table.add_column("Type", justify="center", style="#F7768E", no_wrap=True)
table.add_column("Min", justify="right", style="#F7768E", no_wrap=True)
table.add_column("Max", justify="left", style="#F7768E", no_wrap=True)
for env in missing:
table.add_row(
env,
explanations[env] if env in explanations.keys() else "No explanation given",
str(types[env].__name__) if env in types.keys() else "str",
str(bounds[env][0]) if env in bounds.keys() and bounds[env][1] is not None else "",
str(bounds[env][1])
if env in bounds.keys() and len(bounds[env]) > 1 and bounds[env][1] is not None
else "",
)
console.print(table)
success = False success = False
if len(incorrect): if len(incorrect):
console.print( table = Table(
f"[red]{'These variables are'*(len(incorrect) > 1) or 'This variable is'} set incorrectly: " title="Incorrect variables",
+ "\n".join(incorrect) highlight=True,
show_lines=True,
box=box.ROUNDED,
border_style="#414868",
header_style="#C0CAF5 bold",
title_justify="left",
title_style="#C0CAF5 bold",
) )
success = False table.add_column("Variable", justify="left", style="#7AA2F7 bold", no_wrap=True)
# if success is True: table.add_column("Current value", justify="left", style="#F7768E", no_wrap=False)
# return True table.add_column("Explanation", justify="left", style="#BB9AF7", no_wrap=False)
# console.print("[green]Do you want to enter the missing variables by hand(y/n)") table.add_column("Type", justify="center", style="#F7768E", no_wrap=True)
# if not input().casefold().startswith("y"): table.add_column("Min", justify="right", style="#F7768E", no_wrap=True)
# console.print("[red]Aborting: Unresolved missing variables") table.add_column("Max", justify="left", style="#F7768E", no_wrap=True)
# return success for env in incorrect:
# with open(".env", "a") as env_file: table.add_row(
# for env in missing: env,
# pass os.getenv(env),
return success explanations[env] if env in explanations.keys() else "No explanation given",
str(types[env].__name__) if env in types.keys() else "str",
str(bounds[env][0]) if env in bounds.keys() else "None",
str(bounds[env][1]) if env in bounds.keys() and len(bounds[env]) > 1 else "None",
)
missing.add(env)
console.print(table)
if success is True:
return True
console.print(
"[green]Do you want to automatically overwrite incorrect variables and add the missing variables? (y/n)"
)
if not input().casefold().startswith("y"):
console.print("[red]Aborting: Unresolved missing variables")
return False
if len(incorrect):
with open(".env", "r+") as env_file:
lines = []
for line in env_file.readlines():
line.split("=")[0].strip() not in incorrect and lines.append(line)
env_file.seek(0)
env_file.write("\n".join(lines))
env_file.truncate()
console.print("[green]Successfully removed incorrectly set variables from .env")
with open(".env", "a") as env_file:
for env in missing:
env_file.write(
env
+ "="
+ ('"' if env not in types.keys() else "")
+ str(
handle_input(
"[#F7768E bold]" + env + "[#C0CAF5 bold]=",
types[env] if env in types.keys() else False,
matching[env] if env in matching.keys() else ".*",
explanations[env]
if env in explanations.keys()
else "Incorrect input. Try again.",
bounds[env][0] if env in bounds.keys() else None,
bounds[env][1] if env in bounds.keys() and len(bounds[env]) > 1 else None,
oob_errors[env] if env in oob_errors.keys() else "Input too long/short.",
extra_info="[#C0CAF5 bold]⮶ "
+ (
explanations[env] if env in explanations.keys() else "No info available"
),
)
)
+ ('"' if env not in types.keys() else "")
+ "\n"
)
return True
if __name__ == "__main__": if __name__ == "__main__":

@ -36,10 +36,13 @@ def handle_input(
nmin=None, nmin=None,
nmax=None, nmax=None,
oob_error="", oob_error="",
extra_info="",
): ):
match = re.compile(match + "$") match = re.compile(match + "$")
console.print(extra_info, no_wrap=True)
while True: while True:
user_input = input(message + "\n> ").strip() console.print(message, end="")
user_input = input("").strip()
if re.match(match, user_input) is not None: if re.match(match, user_input) is not None:
if check_type is not False: if check_type is not False:
try: try:

Loading…
Cancel
Save