diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml new file mode 100644 index 0000000..759d90e --- /dev/null +++ b/.github/workflows/python-app.yml @@ -0,0 +1,36 @@ +# This workflow will install Python dependencies, run tests and lint with a single version of Python +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Python application + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.10 + uses: actions/setup-python@v2 + with: + python-version: "3.10" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install flake8 pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Test with pytest + run: | + pytest diff --git a/.gitignore b/.gitignore index daccbf6..2ec981d 100644 --- a/.gitignore +++ b/.gitignore @@ -113,6 +113,9 @@ dmypy.json # Pyre type checker .pyre/ +# VS Code +.vscode/ + # Ignore config files config.ini diff --git a/README.md b/README.md index 9bb2209..93271b3 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,10 @@ A Tool to help post on various social media simultaneously ## Quick Start guide 1. Install dependencies using `pip install -r requirements.txt` -2. Start the website by running `python3 .` +2. Start the website by running `python3 flaskr` 3. Stop the website using `Ctrl+C` 4. Fill up the configuration under `config.ini` based on the guide below -5. Run the server again by running `python3 .` +5. Run the server again by running `python3 flaskr` 6. Navigate to [`http://localhost:5000/`](http://localhost:5000/) 7. Fill up the form diff --git a/flaskr/__init__.py b/flaskr/__init__.py new file mode 100644 index 0000000..d3efdaf --- /dev/null +++ b/flaskr/__init__.py @@ -0,0 +1 @@ +from .__main__ import app \ No newline at end of file diff --git a/flaskr/__main__.py b/flaskr/__main__.py new file mode 100644 index 0000000..abe2ac7 --- /dev/null +++ b/flaskr/__main__.py @@ -0,0 +1,46 @@ +"""The frontend for the social media manager""" +import os +import configparser + + +try: + from constants import DEFAULT_CONFIG_FILE, UPLOAD_FOLDER + from app import app +except ImportError: + from .constants import DEFAULT_CONFIG_FILE, UPLOAD_FOLDER + from .app import app + + +def create_default_config() -> None: + """Create a default configuration file""" + config = configparser.ConfigParser() + # config["twitter"] = { + # "api_key": "", + # "api_secret": "", + # "access_token": "", + # "access_token_secret": "", + # "bearer_token": "", + # } + config["facebook"] = { + "token": "", + "group_id": "", + } + config["telegram"] = { + "token": "", + "group_id": "", + } + with open(DEFAULT_CONFIG_FILE, "w") as configfile: + config.write(configfile) + + +if __name__ == "__main__": + if not os.path.exists(DEFAULT_CONFIG_FILE): + create_default_config() + credentials = configparser.ConfigParser() + credentials.read(DEFAULT_CONFIG_FILE) + + # Check if upload folder exists + if not os.path.exists(UPLOAD_FOLDER): + os.mkdir(UPLOAD_FOLDER) + + app.run(debug=False) diff --git a/__main__.py b/flaskr/app.py similarity index 84% rename from __main__.py rename to flaskr/app.py index 1ea9df0..6575e77 100644 --- a/__main__.py +++ b/flaskr/app.py @@ -3,36 +3,63 @@ import os import configparser from flask import Flask, abort, render_template, request, redirect, flash, Response -from functools import partial from werkzeug.utils import secure_filename -from constants import ( - BODY_KEY, - CSV_KEY, - EMAIL_KEY, - ERROR_FLASH, - FACEBOOK, - IMAGE_KEY, - INFO_FLASH, - SOCIAL_MEDIA, - HOME_PAGE, - SELECT_AT_LEAST_ONE_SOCIAL_MEDIA, - SUBJECT_KEY, - SUCCESS_MESSAGE, - EMPTY_CONTENT, - CONTENT_KEY, - EMPTY_STRING, - DEFAULT_CONFIG_FILE, - TELEGRAM, - TWITTER, - EMAIL_PAGE, - UPLOAD_FOLDER, -) -from tools.post import post_to_facebook, post_to_telegram, post_to_twitter -from tools.email.email_sc import EmailIntegration, create_email -from tools.email import extract_csv -from tools.utils import replace_string +try: + from constants import ( + BODY_KEY, + CSV_KEY, + EMAIL_KEY, + ERROR_FLASH, + FACEBOOK, + IMAGE_KEY, + INFO_FLASH, + SOCIAL_MEDIA, + HOME_PAGE, + SELECT_AT_LEAST_ONE_SOCIAL_MEDIA, + SUBJECT_KEY, + SUCCESS_MESSAGE, + EMPTY_CONTENT, + CONTENT_KEY, + EMPTY_STRING, + DEFAULT_CONFIG_FILE, + TELEGRAM, + TWITTER, + EMAIL_PAGE, + UPLOAD_FOLDER, + ) + from tools.post import post_to_facebook, post_to_telegram, post_to_twitter + from tools.email.email_sc import EmailIntegration, create_email + from tools.email import extract_csv + from tools.utils import replace_string +except ImportError as e: + from .constants import ( + BODY_KEY, + CSV_KEY, + EMAIL_KEY, + ERROR_FLASH, + FACEBOOK, + IMAGE_KEY, + INFO_FLASH, + SOCIAL_MEDIA, + HOME_PAGE, + SELECT_AT_LEAST_ONE_SOCIAL_MEDIA, + SUBJECT_KEY, + SUCCESS_MESSAGE, + EMPTY_CONTENT, + CONTENT_KEY, + EMPTY_STRING, + DEFAULT_CONFIG_FILE, + TELEGRAM, + TWITTER, + EMAIL_PAGE, + UPLOAD_FOLDER, + ) + from .tools.post import post_to_facebook, post_to_telegram, post_to_twitter + from .tools.email.email_sc import EmailIntegration, create_email + from .tools.email import extract_csv + from .tools.utils import replace_string # Set up logger logging.basicConfig( diff --git a/constants.py b/flaskr/constants.py similarity index 100% rename from constants.py rename to flaskr/constants.py diff --git a/templates/base.html b/flaskr/templates/base.html similarity index 100% rename from templates/base.html rename to flaskr/templates/base.html diff --git a/templates/email.html b/flaskr/templates/email.html similarity index 100% rename from templates/email.html rename to flaskr/templates/email.html diff --git a/templates/index.html b/flaskr/templates/index.html similarity index 100% rename from templates/index.html rename to flaskr/templates/index.html diff --git a/templates/nav.html b/flaskr/templates/nav.html similarity index 100% rename from templates/nav.html rename to flaskr/templates/nav.html diff --git a/tools/__init__.py b/flaskr/tools/__init__.py similarity index 100% rename from tools/__init__.py rename to flaskr/tools/__init__.py diff --git a/tools/email/__init__.py b/flaskr/tools/email/__init__.py similarity index 100% rename from tools/email/__init__.py rename to flaskr/tools/email/__init__.py diff --git a/tools/email/constants.py b/flaskr/tools/email/constants.py similarity index 100% rename from tools/email/constants.py rename to flaskr/tools/email/constants.py diff --git a/tools/email/email_sc.py b/flaskr/tools/email/email_sc.py similarity index 100% rename from tools/email/email_sc.py rename to flaskr/tools/email/email_sc.py diff --git a/tools/email/utils.py b/flaskr/tools/email/utils.py similarity index 100% rename from tools/email/utils.py rename to flaskr/tools/email/utils.py diff --git a/tools/facebook_bot/FacebookBot.py b/flaskr/tools/facebook_bot/FacebookBot.py similarity index 100% rename from tools/facebook_bot/FacebookBot.py rename to flaskr/tools/facebook_bot/FacebookBot.py diff --git a/tools/facebook_bot/__init__.py b/flaskr/tools/facebook_bot/__init__.py similarity index 100% rename from tools/facebook_bot/__init__.py rename to flaskr/tools/facebook_bot/__init__.py diff --git a/tools/facebook_bot/constants.py b/flaskr/tools/facebook_bot/constants.py similarity index 100% rename from tools/facebook_bot/constants.py rename to flaskr/tools/facebook_bot/constants.py diff --git a/tools/facebook_bot/utils.py b/flaskr/tools/facebook_bot/utils.py similarity index 100% rename from tools/facebook_bot/utils.py rename to flaskr/tools/facebook_bot/utils.py diff --git a/tools/post.py b/flaskr/tools/post.py similarity index 100% rename from tools/post.py rename to flaskr/tools/post.py diff --git a/tools/telegram_bot/TelegramBot.py b/flaskr/tools/telegram_bot/TelegramBot.py similarity index 100% rename from tools/telegram_bot/TelegramBot.py rename to flaskr/tools/telegram_bot/TelegramBot.py diff --git a/tools/telegram_bot/__init__.py b/flaskr/tools/telegram_bot/__init__.py similarity index 100% rename from tools/telegram_bot/__init__.py rename to flaskr/tools/telegram_bot/__init__.py diff --git a/tools/telegram_bot/__main__.py b/flaskr/tools/telegram_bot/__main__.py similarity index 100% rename from tools/telegram_bot/__main__.py rename to flaskr/tools/telegram_bot/__main__.py diff --git a/tools/telegram_bot/constants.py b/flaskr/tools/telegram_bot/constants.py similarity index 100% rename from tools/telegram_bot/constants.py rename to flaskr/tools/telegram_bot/constants.py diff --git a/tools/telegram_bot/util.py b/flaskr/tools/telegram_bot/util.py similarity index 100% rename from tools/telegram_bot/util.py rename to flaskr/tools/telegram_bot/util.py diff --git a/tools/twitter_bot/TwitterBot.py b/flaskr/tools/twitter_bot/TwitterBot.py similarity index 100% rename from tools/twitter_bot/TwitterBot.py rename to flaskr/tools/twitter_bot/TwitterBot.py diff --git a/tools/twitter_bot/__init__.py b/flaskr/tools/twitter_bot/__init__.py similarity index 100% rename from tools/twitter_bot/__init__.py rename to flaskr/tools/twitter_bot/__init__.py diff --git a/tools/twitter_bot/secrets.py b/flaskr/tools/twitter_bot/secrets.py similarity index 100% rename from tools/twitter_bot/secrets.py rename to flaskr/tools/twitter_bot/secrets.py diff --git a/tools/utils.py b/flaskr/tools/utils.py similarity index 100% rename from tools/utils.py rename to flaskr/tools/utils.py diff --git a/requirements.txt b/requirements.txt index e2ef260..687ac79 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ tweepy facebook-sdk -flask \ No newline at end of file +flask +pytest \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..4e094a5 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,24 @@ +import pytest +from flaskr import app as flask_app + +@pytest.fixture() +def app(): + flask_app.config.update({ + "TESTING": True, + }) + + # other setup can go here + + yield flask_app + + # clean up / reset resources here + + +@pytest.fixture() +def client(app): + return app.test_client() + + +@pytest.fixture() +def runner(app): + return app.test_cli_runner() \ No newline at end of file diff --git a/tests/test_homepage.py b/tests/test_homepage.py new file mode 100644 index 0000000..e9da2eb --- /dev/null +++ b/tests/test_homepage.py @@ -0,0 +1,20 @@ +def test_homepage(client): + """Test homepage.""" + response = client.get("/") + assert response.status_code == 200 + assert "No content provided" not in response.data.decode() + + +def test_empty_post_request_fail(client): + """Test empty post request.""" + response = client.post("/", follow_redirects=True) + assert response.status_code == 200 + assert "No content provided" in response.data.decode() + + +def test_no_social_media_selected_fails(client): + """Test no social media selected.""" + response = client.post("/", data={"content": "test"}, follow_redirects=True) + assert response.status_code == 200 + assert "Please select at least 1 social media" in response.data.decode() +