diff --git a/.vscode/settings.json b/.vscode/settings.json index 9ee86e7..ba77eac 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { "[python]": { - "editor.defaultFormatter": "ms-python.autopep8" + "editor.defaultFormatter": "ms-python.python" }, "python.formatting.provider": "none" } \ No newline at end of file diff --git a/backend/api/companies.py b/backend/api/companies.py new file mode 100644 index 0000000..a690b50 --- /dev/null +++ b/backend/api/companies.py @@ -0,0 +1,24 @@ +import os +import pandas as pd +import numpy as np +from scraper.top100_extractor import programming_crime_list +COMPANIES_CSV_PATH: str = 'scraper/companies.csv' + +def non_nan(a: list[any]) -> list[any]: + return list(filter(lambda a: type(a) == str or not np.isnan(a), a)) + + +def get_companies(root_dir: str) -> list[dict]: + """ + reads the companies.csv file and returns it as a JSON-ifiable object + to return to the frontend. + """ + df = pd.read_csv(os.path.join(root_dir, COMPANIES_CSV_PATH), index_col='ticker') + tickers = pd.Series(programming_crime_list) + df = df.loc[df.index.isin(tickers), :] + df['tags'] = df[['tag 1', 'tag 2', 'tag 3']].values.tolist() + df['tags'] = df['tags'].apply(non_nan) + del df['tag 1'] + del df['tag 2'] + del df['tag 3'] + return df.reset_index().replace({ np.nan: None }).to_dict('records') \ No newline at end of file diff --git a/scraper/top100_extractor.py b/scraper/top100_extractor.py index 9b5477b..55e66e4 100644 --- a/scraper/top100_extractor.py +++ b/scraper/top100_extractor.py @@ -1,102 +1,93 @@ programming_crime_list = [ 'AAPL', - 'MSFT', - 'AMZN', - 'GOOGL', - 'META', - 'BRK-A', - 'TSLA', - 'JPM', - 'JNJ', - 'V', - 'PG', - 'MA', - 'NVDA', - 'UNH', - 'HD', - 'BAC', - 'DIS', - 'PYPL', - 'KO', - 'INTC', - 'VZ', - 'ADBE', - 'NFLX', - 'CRM', - 'PFE', - 'MRK', - 'CMCSA', - 'T', - 'ABT', - 'PEP', - 'XOM', - 'CVX', - 'WMT', - 'CSCO', - 'MDT', 'ABBV', - 'WFC', - 'NEE', - 'TMUS', - 'MCD', - 'TMO', + 'ABT', 'ACN', - 'AVGO', - 'NKE', - 'TGT', - 'UNP', - 'HON', - 'DHR', - 'ORCL', - 'LLY', - 'FIS', - 'COST', - 'LOW', - 'UPS', - 'AMGN', - 'MMM', - 'TXN', - 'BA', - 'BMY', - 'PM', - 'IBM', - 'GILD', - 'ANTM', - 'LMT', + 'ADBE', 'AMAT', - 'SPGI', - 'RTX', - 'CAT', - 'CVS', - 'MO', - 'LIN', - 'GE', - 'CHTR', - 'DUK', - 'GS', - 'CME', - 'ISRG', - 'SPG', - 'FDX', - 'BDX', - 'CCI', - 'DE', - 'CCI', - 'BIDU', - 'GS', + 'AMGN', + 'AMZN', + 'ANTM', 'APD', - 'MCO', - 'MMC', - 'NSC', - 'USB', + 'AVGO', + 'BA', + 'BAC', + 'BDX', + 'BIDU', + 'BMY', + 'CAT', + 'CCI', + 'CHTR', + 'CMCSA', + 'CME', + 'COST', + 'CRM', + 'CSCO', 'CSX', - 'LRCX', - 'SCHW', + 'CVS', + 'CVX', 'D', - 'BDX', - 'EXC', - 'SO', + 'DE', + 'DHR', + 'DIS', 'DUK', - 'BDX', - 'EXC' -] + 'EXC', + 'FDX', + 'FIS', + 'GE', + 'GILD', + 'GOOGL', + 'GS', + 'HD', + 'HON', + 'IBM', + 'INTC', + 'ISRG', + 'JNJ', + 'JPM', + 'KO', + 'LIN', + 'LLY', + 'LMT', + 'LOW', + 'LRCX', + 'MA', + 'MCD', + 'MCO', + 'MDT', + 'MMC', + 'MMM', + 'MO', + 'MRK', + 'MSFT', + 'NEE', + 'NFLX', + 'NKE', + 'NSC', + 'NVDA', + 'ORCL', + 'PEP', + 'PFE', + 'PG', + 'PM', + 'PYPL', + 'SCHW', + 'SO', + 'SPG', + 'SPGI', + 'T', + 'TGT', + 'TMO', + 'TMUS', + 'TSLA', + 'TXN', + 'UNH', + 'UNP', + 'UPS', + 'USB', + 'V', + 'VZ', + 'WFC', + 'WMT', + 'XOM' +] \ No newline at end of file diff --git a/stockingly-frontend/package.json b/stockingly-frontend/package.json index 5eb2fe8..4aae167 100644 --- a/stockingly-frontend/package.json +++ b/stockingly-frontend/package.json @@ -14,7 +14,7 @@ "roboto-fontface": "*", "vue": "^3.2.0", "vue-router": "^4.0.0", - "vuetify": "^3.0.0", + "vuetify": "^3.2.3", "webfontloader": "^1.0.0" }, "devDependencies": { diff --git a/stockingly-frontend/src/api/index.ts b/stockingly-frontend/src/api/index.ts new file mode 100644 index 0000000..2dbc27e --- /dev/null +++ b/stockingly-frontend/src/api/index.ts @@ -0,0 +1,19 @@ +const BACKEND_URL = "http://localhost:5000"; + +export interface Company { + ceo: string; + "company name": string; + description: string; + exchange: string; + industry: string; + logo: string; + "market cap": number; + sector: string; + "short name": string; + tags: string[]; + ticker: string; + website: string; +} + +export const getCompanies = (): Promise => + fetch(BACKEND_URL + '/companies').then(r => r.json()) \ No newline at end of file diff --git a/stockingly-frontend/src/plugins/vuetify.ts b/stockingly-frontend/src/plugins/vuetify.ts index 4e482cf..dfe18e0 100644 --- a/stockingly-frontend/src/plugins/vuetify.ts +++ b/stockingly-frontend/src/plugins/vuetify.ts @@ -10,9 +10,13 @@ import 'vuetify/styles' // Composables import { createVuetify } from 'vuetify' +import { VSkeletonLoader } from 'vuetify/labs/VSkeletonLoader' // https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides export default createVuetify({ + components: { + VSkeletonLoader + }, theme: { defaultTheme: 'light', themes: { diff --git a/stockingly-frontend/src/views/Home.vue b/stockingly-frontend/src/views/Home.vue index 8d3d651..1ac6d2a 100644 --- a/stockingly-frontend/src/views/Home.vue +++ b/stockingly-frontend/src/views/Home.vue @@ -1,6 +1,59 @@ diff --git a/stockingly-frontend/yarn.lock b/stockingly-frontend/yarn.lock index 568dad0..4117c14 100644 --- a/stockingly-frontend/yarn.lock +++ b/stockingly-frontend/yarn.lock @@ -1641,10 +1641,10 @@ vue@^3.2.0: "@vue/server-renderer" "3.2.47" "@vue/shared" "3.2.47" -vuetify@^3.0.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/vuetify/-/vuetify-3.2.2.tgz#a4a39bec15e96b4f9f9be6353e19f156abd91c35" - integrity sha512-syFfeZVH6dycltqVCx4tDn68fR3r697+Jt7vJW1l3i9a5ClnwpdRBWtE6dt2bjClS2K/VpWYt+rAsLiG7sGU/g== +vuetify@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/vuetify/-/vuetify-3.2.3.tgz#05767c3d88068654b757d33789b8c249f1d38e00" + integrity sha512-o7IJm/P5Ttp9ItF1ytQihsLzv4jxIYVfI4Ypkkqc4A7N2MeTmkDOPGbDNUgJ+G1p2upL00LCbc73A9YM8xYVpg== webfontloader@^1.0.0: version "1.6.28" diff --git a/stockingly.py b/stockingly.py index 39698a7..3ed9e56 100644 --- a/stockingly.py +++ b/stockingly.py @@ -1,10 +1,13 @@ from flask import Flask, jsonify, redirect, url_for, send_from_directory from flask_cors import CORS from backend.utils.build_frontend import build_frontend +from backend.api.companies import get_companies import os import subprocess +ROOT_DIR: str = os.path.dirname(__file__) + # instantiate the app app = Flask(__name__, static_url_path='/static', static_folder='stockingly-frontend/dist') app.config.from_object(__name__) @@ -18,6 +21,11 @@ def index(): return redirect(url_for('static', filename='index.html')) +@app.route('/companies', methods=['GET']) +def companies() -> object: + return jsonify(get_companies(ROOT_DIR)) + + if __name__ == '__main__': build_frontend() app.run()