commit 2421fcf9007b93c42e252b543fb7a3eb0856f294 Author: samerbam Date: Tue Aug 22 19:51:39 2023 -0400 Init diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..c0fe8ca Binary files /dev/null and b/.DS_Store differ diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..b8ef8f6 --- /dev/null +++ b/.env.example @@ -0,0 +1,4 @@ +AUTH0_DOMAIN = your.domain.auth0.com +AUTH0_API_AUDIENCE = your.api.audience +AUTH0_ISSUER = https://your.domain.auth0.com/ +AUTH0_ALGORITHMS = RS256 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6ffbc3f --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.env +venv +.venv +.idea \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..8d62c1c --- /dev/null +++ b/README.md @@ -0,0 +1,86 @@ +# Auth0 + Python + FastAPI API Seed + +This is the seed project you need to use if you're going to create an API using FastAPI in Python and Auth0. If you just want to create a Regular Python WebApp, please check [this project](https://github.com/auth0-samples/auth0-python-web-app/tree/master/01-Login) + +## Running the example + +In order to run the example you need to have `python3` (any version higher than `3.6`) and `pip3` installed. + +### Configuration + +The configuration you'll need is mostly information from Auth0, you'll need both the tentant domain and the API information. + +This app reads its configuration information from a `.env` file by default. + +To create a `.env` file you can copy the `.env.example` file and fill the values accordingly: + +```console +cp .env.example .env +``` + +Alternatively you can use environment variables to define your application's settings (remember to update the values accordingly): + +```console +export AUTH0_DOMAIN='your.domain.auth0.com' +export AUTH0_API_AUDIENCE='your.api.audience' +export AUTH0_ISSUER='https://your.domain.auth0.com' +export AUTH0_ALGORITHMS='RS256' +``` + +### Spin up the server + +Once you've set your environment information below you'll find the commands you'll need. + +1. Create and activate a python environment: + +```console +python3 -m venv .venv +source .venv/bin/activate +``` + +2. Install the needed dependencies with: + +```console +pip install -r requirements.txt +``` +3. Start the server with the following: + +```console +uvicorn application.main:app +``` + +4. Try calling [http://localhost:8000/api/public](http://localhost:8000/api/public) + +``` +curl -X 'GET' \ + 'http://localhost:8000/api/public' \ + -H 'accept: application/json' +``` + +## API documentation + +Access [http://localhost:8000/docs](http://localhost:8000/docs). From there you'll see all endpoints and can test your API + +### Testing the API + +#### Private endpoint + +You can then try to do a GET to [http://localhost:8000/api/private](http://localhost:8000/api/private) which will throw an error if you don't send an access token signed with RS256 with the appropriate issuer and audience in the Authorization header. + +```console +curl -X 'GET' \ + 'http://localhost:8000/api/private' \ + -H 'accept: application/json' \ + -H 'Authorization: Bearer ' +``` + +#### Private-Scoped endpoint + +You can also try to do a GET to [http://localhost:8000/api/private-scoped](http://localhost:8000/api/private-scoped) which will throw an error if you don't send an access token with the scope `read:messages` signed with RS256 with the appropriate issuer and audience in the Authorization header. + +```console +curl -X 'GET' \ + 'http://localhost:8000/api/private-scoped' \ + -H 'accept: application/json' \ + -H 'Authorization: Bearer ' +``` diff --git a/application/.DS_Store b/application/.DS_Store new file mode 100644 index 0000000..9564032 Binary files /dev/null and b/application/.DS_Store differ diff --git a/application/IBMPlexMono-Bold.ttf b/application/IBMPlexMono-Bold.ttf new file mode 100644 index 0000000..2e437e2 Binary files /dev/null and b/application/IBMPlexMono-Bold.ttf differ diff --git a/application/IBMPlexMono-Medium.ttf b/application/IBMPlexMono-Medium.ttf new file mode 100644 index 0000000..39f178d Binary files /dev/null and b/application/IBMPlexMono-Medium.ttf differ diff --git a/application/IBM_Plex_Mono.zip b/application/IBM_Plex_Mono.zip new file mode 100644 index 0000000..5b580ba Binary files /dev/null and b/application/IBM_Plex_Mono.zip differ diff --git a/application/IBM_Plex_Mono/.DS_Store b/application/IBM_Plex_Mono/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/application/IBM_Plex_Mono/.DS_Store differ diff --git a/application/IBM_Plex_Mono/IBMPlexMono-BoldItalic.ttf b/application/IBM_Plex_Mono/IBMPlexMono-BoldItalic.ttf new file mode 100644 index 0000000..f2695fc Binary files /dev/null and b/application/IBM_Plex_Mono/IBMPlexMono-BoldItalic.ttf differ diff --git a/application/IBM_Plex_Mono/IBMPlexMono-ExtraLight.ttf b/application/IBM_Plex_Mono/IBMPlexMono-ExtraLight.ttf new file mode 100644 index 0000000..573ef76 Binary files /dev/null and b/application/IBM_Plex_Mono/IBMPlexMono-ExtraLight.ttf differ diff --git a/application/IBM_Plex_Mono/IBMPlexMono-ExtraLightItalic.ttf b/application/IBM_Plex_Mono/IBMPlexMono-ExtraLightItalic.ttf new file mode 100644 index 0000000..ea13f86 Binary files /dev/null and b/application/IBM_Plex_Mono/IBMPlexMono-ExtraLightItalic.ttf differ diff --git a/application/IBM_Plex_Mono/IBMPlexMono-Italic.ttf b/application/IBM_Plex_Mono/IBMPlexMono-Italic.ttf new file mode 100644 index 0000000..3cb28a3 Binary files /dev/null and b/application/IBM_Plex_Mono/IBMPlexMono-Italic.ttf differ diff --git a/application/IBM_Plex_Mono/IBMPlexMono-Light.ttf b/application/IBM_Plex_Mono/IBMPlexMono-Light.ttf new file mode 100644 index 0000000..df167f0 Binary files /dev/null and b/application/IBM_Plex_Mono/IBMPlexMono-Light.ttf differ diff --git a/application/IBM_Plex_Mono/IBMPlexMono-LightItalic.ttf b/application/IBM_Plex_Mono/IBMPlexMono-LightItalic.ttf new file mode 100644 index 0000000..c9072e9 Binary files /dev/null and b/application/IBM_Plex_Mono/IBMPlexMono-LightItalic.ttf differ diff --git a/application/IBM_Plex_Mono/IBMPlexMono-MediumItalic.ttf b/application/IBM_Plex_Mono/IBMPlexMono-MediumItalic.ttf new file mode 100644 index 0000000..0d887f7 Binary files /dev/null and b/application/IBM_Plex_Mono/IBMPlexMono-MediumItalic.ttf differ diff --git a/application/IBM_Plex_Mono/IBMPlexMono-Regular.ttf b/application/IBM_Plex_Mono/IBMPlexMono-Regular.ttf new file mode 100644 index 0000000..81ca3dc Binary files /dev/null and b/application/IBM_Plex_Mono/IBMPlexMono-Regular.ttf differ diff --git a/application/IBM_Plex_Mono/IBMPlexMono-SemiBold.ttf b/application/IBM_Plex_Mono/IBMPlexMono-SemiBold.ttf new file mode 100644 index 0000000..73dd5a4 Binary files /dev/null and b/application/IBM_Plex_Mono/IBMPlexMono-SemiBold.ttf differ diff --git a/application/IBM_Plex_Mono/IBMPlexMono-SemiBoldItalic.ttf b/application/IBM_Plex_Mono/IBMPlexMono-SemiBoldItalic.ttf new file mode 100644 index 0000000..a41b0d3 Binary files /dev/null and b/application/IBM_Plex_Mono/IBMPlexMono-SemiBoldItalic.ttf differ diff --git a/application/IBM_Plex_Mono/IBMPlexMono-Thin.ttf b/application/IBM_Plex_Mono/IBMPlexMono-Thin.ttf new file mode 100644 index 0000000..e173f5a Binary files /dev/null and b/application/IBM_Plex_Mono/IBMPlexMono-Thin.ttf differ diff --git a/application/IBM_Plex_Mono/IBMPlexMono-ThinItalic.ttf b/application/IBM_Plex_Mono/IBMPlexMono-ThinItalic.ttf new file mode 100644 index 0000000..8529275 Binary files /dev/null and b/application/IBM_Plex_Mono/IBMPlexMono-ThinItalic.ttf differ diff --git a/application/IBM_Plex_Mono/OFL.txt b/application/IBM_Plex_Mono/OFL.txt new file mode 100644 index 0000000..379e735 --- /dev/null +++ b/application/IBM_Plex_Mono/OFL.txt @@ -0,0 +1,93 @@ +Copyright © 2017 IBM Corp. with Reserved Font Name "Plex" + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/application/__pycache__/config.cpython-311.pyc b/application/__pycache__/config.cpython-311.pyc new file mode 100644 index 0000000..0458a53 Binary files /dev/null and b/application/__pycache__/config.cpython-311.pyc differ diff --git a/application/__pycache__/database.cpython-311.pyc b/application/__pycache__/database.cpython-311.pyc new file mode 100644 index 0000000..af9de4d Binary files /dev/null and b/application/__pycache__/database.cpython-311.pyc differ diff --git a/application/__pycache__/main.cpython-311.pyc b/application/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000..a6438f6 Binary files /dev/null and b/application/__pycache__/main.cpython-311.pyc differ diff --git a/application/__pycache__/sudoku_generator.cpython-311.pyc b/application/__pycache__/sudoku_generator.cpython-311.pyc new file mode 100644 index 0000000..afdc7da Binary files /dev/null and b/application/__pycache__/sudoku_generator.cpython-311.pyc differ diff --git a/application/__pycache__/thermal_print.cpython-311.pyc b/application/__pycache__/thermal_print.cpython-311.pyc new file mode 100644 index 0000000..28935e4 Binary files /dev/null and b/application/__pycache__/thermal_print.cpython-311.pyc differ diff --git a/application/__pycache__/utils.cpython-311.pyc b/application/__pycache__/utils.cpython-311.pyc new file mode 100644 index 0000000..93119a6 Binary files /dev/null and b/application/__pycache__/utils.cpython-311.pyc differ diff --git a/application/__pycache__/wordsearch_generator.cpython-311.pyc b/application/__pycache__/wordsearch_generator.cpython-311.pyc new file mode 100644 index 0000000..ab4445e Binary files /dev/null and b/application/__pycache__/wordsearch_generator.cpython-311.pyc differ diff --git a/application/config.py b/application/config.py new file mode 100644 index 0000000..ddfcd96 --- /dev/null +++ b/application/config.py @@ -0,0 +1,18 @@ +from functools import lru_cache + +from pydantic_settings import BaseSettings + + +class Settings(BaseSettings): + auth0_domain: str + auth0_api_audience: str + auth0_issuer: str + auth0_algorithms: str + + class Config: + env_file = ".env" + + +@lru_cache() +def get_settings(): + return Settings() diff --git a/application/data.json b/application/data.json new file mode 100644 index 0000000..fff3cea --- /dev/null +++ b/application/data.json @@ -0,0 +1 @@ +{"quotes": [{"q": "A goal is a dream with a deadline.", "a": "Napoleon Hill", "c": "34", "h": "
“A goal is a dream with a deadline.” —
Napoleon Hill
"}, {"q": "The whole of life, from the moment you are born to the moment you die, is a process of learning.", "a": "Jiddu Krishnamurti", "c": "96", "h": "
“The whole of life, from the moment you are born to the moment you die, is a process of learning.” —
Jiddu Krishnamurti
"}, {"q": "Anything you may hold firmly in your imagination can be yours.", "a": "William James", "c": "62", "h": "
“Anything you may hold firmly in your imagination can be yours.” —
William James
"}, {"q": "We must embrace pain and burn it as fuel for our journey.", "a": "Kenji Miyazawa", "c": "57", "h": "
“We must embrace pain and burn it as fuel for our journey.” —
Kenji Miyazawa
"}, {"q": "My guiding principle is this: Guilt is never to be doubted. ", "a": "Franz Kafka", "c": "60", "h": "
“My guiding principle is this: Guilt is never to be doubted. ” —
Franz Kafka
"}, {"q": "There is a cosmic law which says that every satisfaction must be paid for with a dissatisfaction.", "a": "G.I. Gurdjieff", "c": "97", "h": "
“There is a cosmic law which says that every satisfaction must be paid for with a dissatisfaction.” —
G.I. Gurdjieff
"}, {"q": "If what you're doing is not your passion, you have nothing to lose.", "a": "Celestine Chua", "c": "67", "h": "
“If what you're doing is not your passion, you have nothing to lose.” —
Celestine Chua
"}, {"q": "Patience is a bitter plant, but its fruit is sweet.", "a": "Chinese Proverb", "c": "51", "h": "
“Patience is a bitter plant, but its fruit is sweet.” —
Chinese Proverb
"}, {"q": "To lose your temper is only useful once a year.", "a": "Colin R. Davis", "c": "47", "h": "
“To lose your temper is only useful once a year.” —
Colin R. Davis
"}, {"q": "Do not follow the ideas of others, but learn to listen to the voice within yourself.", "a": "Dogen", "c": "84", "h": "
“Do not follow the ideas of others, but learn to listen to the voice within yourself.” —
Dogen
"}, {"q": "No problem can be solved from the same level of consciousness that created it.", "a": "Albert Einstein", "c": "78", "h": "
“No problem can be solved from the same level of consciousness that created it.” —
Albert Einstein
"}, {"q": "When you stop questioning, you stop learning.", "a": "Lolly Daskal", "c": "45", "h": "
“When you stop questioning, you stop learning.” —
Lolly Daskal
"}, {"q": "The way of success is the way of continuous pursuit of knowledge.", "a": "Napoleon Hill", "c": "65", "h": "
“The way of success is the way of continuous pursuit of knowledge.” —
Napoleon Hill
"}, {"q": "The question is not what you look at, but what you see.", "a": "Henry David Thoreau", "c": "55", "h": "
“The question is not what you look at, but what you see.” —
Henry David Thoreau
"}, {"q": "Be kind, for everyone you meet is fighting a harder battle.", "a": "Plato", "c": "59", "h": "
“Be kind, for everyone you meet is fighting a harder battle.” —
Plato
"}, {"q": "No matter how qualified or deserving we are, we will never reach a better life until we can imagine it for ourselves and allow ourselves to have it.", "a": "Richard Bach", "c": "148", "h": "
“No matter how qualified or deserving we are, we will never reach a better life until we can imagine it for ourselves and allow ourselves to have it.” —
Richard Bach
"}, {"q": "When you are able to employ your will always for constructive purposes, you become the controller of your destiny.", "a": "Paramahansa Yogananda", "c": "114", "h": "
“When you are able to employ your will always for constructive purposes, you become the controller of your destiny.” —
Paramahansa Yogananda
"}, {"q": "You are not stuck where you are unless you decide to be. ", "a": "Wayne Dyer", "c": "58", "h": "
“You are not stuck where you are unless you decide to be. ” —
Wayne Dyer
"}, {"q": "We crave for new sensations but soon become indifferent to them. The wonders of yesterday are today common occurrences ", "a": "Nikola Tesla", "c": "119", "h": "
“We crave for new sensations but soon become indifferent to them. The wonders of yesterday are today common occurrences ” —
Nikola Tesla
"}, {"q": "The day is for honest men, the night for thieves.", "a": "Euripides", "c": "49", "h": "
“The day is for honest men, the night for thieves.” —
Euripides
"}, {"q": "Life is a traveling to the edge of knowledge, then a leap taken.", "a": "D. H. Lawrence", "c": "64", "h": "
“Life is a traveling to the edge of knowledge, then a leap taken.” —
D. H. Lawrence
"}, {"q": "Cherish forever what makes you unique, cuz you're really a yawn if it goes.", "a": "Bette Midler", "c": "75", "h": "
“Cherish forever what makes you unique, cuz you're really a yawn if it goes.” —
Bette Midler
"}, {"q": "How much pain they have cost us, the evils which have never happened.", "a": "Thomas Jefferson", "c": "69", "h": "
“How much pain they have cost us, the evils which have never happened.” —
Thomas Jefferson
"}, {"q": "All know the way; few actually walk it. ", "a": "Bodhidharma", "c": "40", "h": "
“All know the way; few actually walk it. ” —
Bodhidharma
"}, {"q": "In spite of everything, I shall rise again.", "a": "Vincent van Gogh", "c": "43", "h": "
“In spite of everything, I shall rise again.” —
Vincent van Gogh
"}, {"q": "Continuous effort - not strength or intelligence - is the key to unlocking our potential.", "a": "Winston Churchill", "c": "89", "h": "
“Continuous effort - not strength or intelligence - is the key to unlocking our potential.” —
Winston Churchill
"}, {"q": "To acquire true self power you have to feel beneath no one, be immune to criticism and be fearless.", "a": "Deepak Chopra", "c": "99", "h": "
“To acquire true self power you have to feel beneath no one, be immune to criticism and be fearless.” —
Deepak Chopra
"}, {"q": "If I love myself I love you. If I love you I love myself.", "a": "Rumi", "c": "57", "h": "
“If I love myself I love you. If I love you I love myself.” —
Rumi
"}, {"q": "It's easy to wish for health when you're sick. When you're doing well, you need just as much vigilance.", "a": "Kamal Ravikant", "c": "104", "h": "
“It's easy to wish for health when you're sick. When you're doing well, you need just as much vigilance.” —
Kamal Ravikant
"}, {"q": "If you can't fly, run. If you can't run, walk. If you can't walk, crawl, but by all means, keep moving.", "a": "Martin Luther King, Jr.", "c": "103", "h": "
“If you can't fly, run. If you can't run, walk. If you can't walk, crawl, but by all means, keep moving.” —
Martin Luther King, Jr.
"}, {"q": "The wisest men follow their own direction.", "a": "Euripides", "c": "42", "h": "
“The wisest men follow their own direction.” —
Euripides
"}, {"q": "Circumstances do not make the man, they reveal him.", "a": "James Allen", "c": "51", "h": "
“Circumstances do not make the man, they reveal him.” —
James Allen
"}, {"q": "No snowflake ever falls in the wrong place.", "a": "Zen Proverb", "c": "43", "h": "
“No snowflake ever falls in the wrong place.” —
Zen Proverb
"}, {"q": "We ourselves feel that what we are doing is just a drop in the ocean. But the ocean would be less because of that missing drop.", "a": "Mother Teresa", "c": "127", "h": "
“We ourselves feel that what we are doing is just a drop in the ocean. But the ocean would be less because of that missing drop.” —
Mother Teresa
"}, {"q": "They who have conquered doubt and fear have conquered failure.", "a": "James Allen", "c": "62", "h": "
“They who have conquered doubt and fear have conquered failure.” —
James Allen
"}, {"q": "Your home is where your thoughts find peace.", "a": "Zen Proverb", "c": "44", "h": "
“Your home is where your thoughts find peace.” —
Zen Proverb
"}, {"q": "I would rather die on my feet than live on my knees.", "a": "Euripides", "c": "52", "h": "
“I would rather die on my feet than live on my knees.” —
Euripides
"}, {"q": "It takes half your life before you discover life is a do-it-yourself project.", "a": "Napoleon Hill", "c": "77", "h": "
“It takes half your life before you discover life is a do-it-yourself project.” —
Napoleon Hill
"}, {"q": "The one who praises you is a thief. The one who criticizes you is your true friend.", "a": "Seungsahn", "c": "83", "h": "
“The one who praises you is a thief. The one who criticizes you is your true friend.” —
Seungsahn
"}, {"q": "Life is like riding a bicycle. To keep your balance you must keep moving.", "a": "Albert Einstein", "c": "73", "h": "
“Life is like riding a bicycle. To keep your balance you must keep moving.” —
Albert Einstein
"}, {"q": "The goal is not to be perfect by the end, the goal is to be better today.", "a": "Simon Sinek", "c": "73", "h": "
“The goal is not to be perfect by the end, the goal is to be better today.” —
Simon Sinek
"}, {"q": "Fashion fades, only style remains the same.", "a": "Coco Chanel", "c": "43", "h": "
“Fashion fades, only style remains the same.” —
Coco Chanel
"}, {"q": "Do not bite at the bait of pleasure, till you know there is no hook beneath it.", "a": "Thomas Jefferson", "c": "79", "h": "
“Do not bite at the bait of pleasure, till you know there is no hook beneath it.” —
Thomas Jefferson
"}, {"q": "Intelligent men are cruel. Stupid men are monstrously cruel.", "a": "Jack London", "c": "60", "h": "
“Intelligent men are cruel. Stupid men are monstrously cruel.” —
Jack London
"}, {"q": "Sadness is but a wall between two gardens.", "a": "Kahlil Gibran", "c": "42", "h": "
“Sadness is but a wall between two gardens.” —
Kahlil Gibran
"}, {"q": "To the world you may be one person; but to one person you may be the world.", "a": "Dr. Seuss", "c": "75", "h": "
“To the world you may be one person; but to one person you may be the world.” —
Dr. Seuss
"}, {"q": "Fools read fast. Geniuses reread.", "a": "Maxime Lagace", "c": "33", "h": "
“Fools read fast. Geniuses reread.” —
Maxime Lagace
"}, {"q": "Be of good cheer about death, and know this of a truth, that no evil can happen to a good man, either in life or after death.", "a": "Socrates", "c": "125", "h": "
“Be of good cheer about death, and know this of a truth, that no evil can happen to a good man, either in life or after death.” —
Socrates
"}, {"q": "The greatest of all mistakes is to do nothing because you think you can only do a little. ", "a": "Zig Ziglar", "c": "91", "h": "
“The greatest of all mistakes is to do nothing because you think you can only do a little. ” —
Zig Ziglar
"}, {"q": "Our greatest fears lie in anticipation.", "a": "Honore de Balzac", "c": "39", "h": "
“Our greatest fears lie in anticipation.” —
Honore de Balzac
"}], "quotes_last_updated": 1692738336.831604} \ No newline at end of file diff --git a/application/database.py b/application/database.py new file mode 100644 index 0000000..817420a --- /dev/null +++ b/application/database.py @@ -0,0 +1,73 @@ +import json +import requests +# from datetime import datetime +import time +import random + +class TodoDatabase: + def __init__(self, filename="data.json"): + self.filename = filename + self.database = {} + try: + with open(self.filename) as f: + self.database = json.load(f) + except: + pass + + def save_todo(self, date, todo, save=True): + if date not in self.database: + # if not len(self.database[date]) > 0: + self.database[date] = [] + if todo.recurring: + self.database["recurring"].append(todo.model_dump()) + self.database[date].append(todo.model_dump()) + + if save: + self._save_database() + + def save_todos(self, date, todos): + for todo in todos: + self.save_todo(date, todo, save=False) + self._save_database() + + def remove_todos(self, date): + if date in self.database: + del self.database[date] + + def read_todos(self, date): + # if self.datebase[date] is None: + # return [] + if date not in self.database: + return [] + return self.database[date] + + def _update_quotes(self): + r = requests.get("https://zenquotes.io/api/quotes") + res = r.json() + + # if "quotes" not in self.database: + self.database["quotes"] = res + self.database["quotes_last_updated"] = time.time() + self._save_database() + + def get_random_quote(self): + # print(time.time()) + if time.time()-self.database["quotes_last_updated"] > 86400: + self._update_quotes() + quote = random.choice(self.database["quotes"]) + + return [quote['q'], "- " + quote['a']] + + + def _save_database(self): + with open(self.filename, 'w') as f: + json.dump(self.database, f) + + +if __name__ == '__main__': + data = TodoDatabase() + # data._update_quotes() + print(data.get_random_quote()) + + + diff --git a/application/main.py b/application/main.py new file mode 100644 index 0000000..f32e579 --- /dev/null +++ b/application/main.py @@ -0,0 +1,148 @@ +"""Python FastAPI Auth0 integration example +""" + +from datetime import datetime +from pydantic import BaseModel + +from fastapi import FastAPI, Security +from fastapi.staticfiles import StaticFiles + +from .utils import VerifyToken +from .database import TodoDatabase +from .thermal_print import ThermalPrinter + +# from wsgiref import simple_server + +# Creates app instance +app = FastAPI() +auth = VerifyToken() +data = TodoDatabase() +# printer = ThermalPrinter() + + + +class Todo(BaseModel): + time: str + task: str + recurring: bool + +class TodoList(BaseModel): + date: str #Always current date OLD TEXT: #Either current date in %Y-%m-%d format or "recurring" for a recurring task + todos: list[Todo] + + +class TodoDate(BaseModel): + date: str + # date: str = datetime.today().strftime('%Y-%m-%d') + + +# @app.get("/api/public") +# def public(): +# """No access token required to access this route""" + +# result = { +# "status": "success", +# "msg": ("Hello from a public endpoint! You don't need to be " +# "authenticated to see this.") +# } +# return result + + +@app.get("/api/todos/get") +def get_todos(date: str = datetime.today().strftime('%Y-%m-%d'), auth_result: str = Security(auth.verify)): + """A valid access token is required to access this route""" + + return { + "todos": data.read_todos(date) + } + + # result = { + # "todos": [ + # {"time": "1:00pm to 2:00pm", "text": "Read a book"}, + # {"time": "2:00pm to 3:00pm", "text": "Go for a walk"} + # ] + # } #TODO: replace with database access + + # return result + + + # return auth_result + + + +@app.post("/api/todos/write") +def write_todos(todos: TodoList, auth_result: str = Security(auth.verify)): + """A valid access token is required to access this route""" + + # result = { + # "todos": [ + # {"time": "1:00pm to 2:00pm", "text": "Read a book"}, + # {"time": "2:00pm to 3:00pm", "text": "Go for a walk"} + # ] + # } #TODO: replace with database write + + # return result + + # data.save_todo() + + print(todos) + + # if todos.date != "recurring": + # data.remove_todos(todos.date) + data.remove_todos(todos.date) + data.save_todos(todos.date, todos.todos) + + return {"result": todos.date} + + # return todos + + +# @app.post("/api/todos/write_recurring") +# def write_todos_recurring(todos: TodoList, auth_result: str = Security(auth.verify)): + +# data.save_todos("recurring", todos.todos) + +# return {"result": "success"} + + +@app.get("/api/todos/print") +def print_todos(date: str = datetime.today().strftime('%Y-%m-%d'), auth_result: str = Security(auth.verify)): + """A valid access token is required to access this route""" + + # result = { + # "todos": [ + # {"time": "1:00pm to 2:00pm", "text": "Read a book"}, + # {"time": "2:00pm to 3:00pm", "text": "Go for a walk"} + # ] + # } #TODO: replace with access to database if no todos provided from request, otherwise print request data + + todos = data.get_todos(date) + printer.print_todos() + + return {"result": "success"} + +# class SaveTodos: +# def on_post(self, req, resp): +# pass #Handle web interface sending updated todo list + +# class PrintTodos: +# def on_post(self, req, resp): +# pass #Handle web interface requesting a print action + + +# @app.get("/api/get_todos-scoped") +# def private_scoped(auth_result: str = Security(auth.verify, scopes=['todos:all'])): +# """A valid access token and an appropriate scope are required to access +# this route +# """ + +# return auth_result + + +app.mount("/", StaticFiles(directory="application/static",html = True), name="static") + + +# if __name__ == '__main__': +# print('ay') +# httpd = simple_server.make_server('127.0.0.1', 8000, app) +# httpd.serve_forever() \ No newline at end of file diff --git a/application/static/index.html b/application/static/index.html new file mode 100644 index 0000000..9d19054 --- /dev/null +++ b/application/static/index.html @@ -0,0 +1,311 @@ + + + + + + + Test + + + + + + + +
+ + + +
+ + + + + + +
    + +

    Tasks • Sat Aug 12, 2023

    + +
  • + +
    + + + + 12pm + Walk to school while jumping on one leg and scratching your head. +
    + +
  • + +
    +
    + + + Add Task +
    +
    +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/application/static/scripts.js b/application/static/scripts.js new file mode 100644 index 0000000..731ea92 --- /dev/null +++ b/application/static/scripts.js @@ -0,0 +1,601 @@ +//