-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Used cosmos as db #1
base: master
Are you sure you want to change the base?
Conversation
app/models/models.py
Outdated
|
||
@staticmethod | ||
def get_user_by_email(user_email): | ||
query = "SELECT * FROM users u where u.email='" + user_email + "'" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cosmos SQL is subject to SQL injection.
Read this: https://en.wikipedia.org/wiki/SQL_injection and this https://michaelhowardsecure.blog/2019/03/05/cosmosdb-and-sql-injection/
And then re-write these queries as parameterized queries: https://azuresdkdocs.blob.core.windows.net/$web/python/azure-cosmos/4.0.0b5/index.html?highlight=parameterized%20queries#query-the-database
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
README.md
Outdated
@@ -1,4 +1,4 @@ | |||
# Flask + React + Postgres Starter | |||
# Flask + React + Cosmos |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like this would be a different sample. So let's chat before you attempt to merge back into this repo. We'll likely create a new one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay. I'll keep it as is for now and change after we chat.
@@ -1,5 +1,7 @@ | |||
import React from "react"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest using https://create-react-app.dev/ to help setup the app, wire up dependencies, and so on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi Jon,
I'm not quite sure what you mean by this. My understanding is that since this is not purely a React app so I can't really just follow the code structure given on that site. From what I've read there, I haven't found any material on integrating React with a framework like Flask; I only came across something on integration with an API backend. Upon Googling 'flask react boilerplate', one of the Github repos that came up was the the one that joshgav used to base his Flask-React-Postgres app on.
Could you elaborate on what you mean here? I'm probably misunderstanding you or missing some pieces of info here.
Thanks!
-Lily
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Create react app is kind of a standard these days for creating react apps, it handles a lot of the stuff that I'm seeing issues with above, like css/js dependency managements, etc. It sets you up with a good base to work from. You can put this on the backlog to do later if you'd like.
app/__init__.py
Outdated
key = app.config["SECRET_KEY"] | ||
uri = app.config["COSMOS_DB_URI"] | ||
|
||
client = CosmosClient(uri, credential=key) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not crazy about having the cosmos client as a global variable for the app. I would like all the "cosmos" stuff to be encapsulated so the app is only coupled to that encapsulation versus directly to cosmos.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, I think. Added a db.py in /utils and kept cosmos things there. Imported the db in models.py to use. I thought this way, if in the future, we want to use other db, we can keep all db things there and just import the appropriate dbs to use in models.py or other scripts.
More changes. Invited Maggie to be collaborator. |
app/models/models.py
Outdated
def __init__(self, task, user_id, status): | ||
self.date = datetime.utcnow().date() | ||
self.id = str(randint(_MIN, _MAX)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would think Cosmos has a way to generate random identifiers for documents - what happens if you just don't assign an id? I would think it would auto generate one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, randint doesn't guarantee unique across all items, so please switch over to using Guid for ids. If you don't provide an "id" field, then Cosmos should auto create an id field and insert a guid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have to add an id to each item you insert into the container according to the docs here.
https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/cosmos/azure-cosmos#insert-data
I'll try to use Guid.
README.md
Outdated
## 1. Setting up Azure Services | ||
First, sign up for a free [Azure](https://azure.microsoft.com/en-us/free/) account if you don't already have one. Sign into https://portal.azure.com. | ||
|
||
[Create a resource group](https://github.com/lilyjma/azurethings/blob/master/createResourceGroup.md) to store the resources that you'll be using here--Azure Cosmos DB and Key vault. Then follow the instructions in the links below to create each resource: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This references your fork directly. Make a relative path please.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought this should be in a repository of its own, because I created a repository called 'azurethings' to store small tutorials/things that I learned about Azure.
README.md
Outdated
1. When creating the database, name it 'team_standup'. For this app, you also need two containers named 'tasks' and 'users'. The [partition key](https://docs.microsoft.com/en-us/azure/cosmos-db/partitioning-overview#choose-partitionkey) for both is '/id'. | ||
2. [Key Vault](https://docs.microsoft.com/en-us/azure/key-vault/quick-create-portal#create-a-vault) | ||
1. This will store the credentials for the resources this app uses. For example, it'll store the key to the cosmos database. This way, you don't reveal any key in your code. | ||
2. You'll add two secrets called 'cosmosKey' and 'cosmosURI' to Key Vault to hold the cosmos key and URI respectively. To find these, click into the Cosmos DB account created, go to 'Keys' tab and get the Primary Key and the URI. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Anytime you use 'cosmos' it should be "Cosmos DB" to adhere to branding
|
||
(Remember to store them in the resource group you created; this will make it easier to clean up the resources in the future.) | ||
|
||
1. [Azure Cosmos DB](https://docs.microsoft.com/en-us/azure/cosmos-db/create-cosmosdb-resources-portal#create-an-azure-cosmos-db-account) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like to include the CLI commands along side the portal instructures or a section which is
Azure Portal
- Portal steps here
Azure CLI
- CLI steps here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CLI commands are also executed on Portal though--in the Cloud Shell. You could also execute CLI commands on your local machine but that requires some extra configuration so I thought it'd be the easiest to just do it on Cloud Shell.
README.md
Outdated
|
||
```az ad sp create-for-rbac --name http://my-applications-url --skip-assignment``` | ||
|
||
Use your web app's url. To find that, click on the app in Portal, go to the 'Overview' tab and look for 'URL' on the top right portion of the page. It looks something like https://myUniqueAppName.azurewebsites.net. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean use your web apps url? In the above or below? Please be explicit in everything you ask the user to do.
cd flask-react-postgres | ||
``` | ||
```bash | ||
git clone https://github.com/lilyjma/Flask-React-Postgres/tree/team_standup_app_cosmos |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this path is right, but doesn't matter for now
app/models/models.py
Outdated
if user and bcrypt.check_password_hash(user.password, password): | ||
return user | ||
users = user_container.query_items( | ||
query="SELECT * FROM users u WHERE u.email = @userEmail AND u.password = @userPassword", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just @ email and @ password should be ok.
app/models/models.py
Outdated
def __init__(self, task, user_id, status): | ||
self.date = datetime.utcnow().date() | ||
self.id = str(randint(_MIN, _MAX)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, randint doesn't guarantee unique across all items, so please switch over to using Guid for ids. If you don't provide an "id" field, then Cosmos should auto create an id field and insert a guid.
return True | ||
except IntegrityError: | ||
except exceptions.CosmosHttpResponseError: # item couldn't be upserted | ||
return False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's do some research on how we want to handle error messages from the model. Typically the UI doesn't want to show the error details, but something to consider, versus just returning false.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh the UI wouldn't just show 'False.' It'll have an error message that's appropriate for the specific situation. Please take a look at the routes.py script.
@@ -1,5 +1,7 @@ | |||
import React from "react"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Create react app is kind of a standard these days for creating react apps, it handles a lot of the stuff that I'm seeing issues with above, like css/js dependency managements, etc. It sets you up with a good base to work from. You can put this on the backlog to do later if you'd like.
enable_cross_partition_query=True, | ||
) | ||
user = list(users)[0] | ||
|
||
return user | ||
|
||
@staticmethod | ||
def get_user_with_email_and_password(email, password): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be using OAuth to manage users and permissions. Having a method with email and password basically means that your app controls user access, permissions, etc and storing of credentials in the database. Typically you avoid with this access tokens and OAuth. It's a bigger more complicated implementation that you should learn, but we can discuss later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I'd love to have a discussion on this. Right now, one problem I'm seeing is that when a user is logged in, he/she can edit other people's tasks, instead of just his/her own. So basically, a logged in user has access to the whole database, instead of just part of it that stores his/her own info. I don't know if this can be solved by OAuth, but the way this works now is not ideal.
Also, can we discuss the create-react-app too, like how to make it integrate with Flask? I didn't change the structure of the code at all. I think the original app is based on this boilerplate that combines Flask and React, which I guess is not ideally structured.
Changed what needs to be done to create a service principal. Previously misunderstood the --name parameter in the command--it just has to be a name that starts with 'http://' and doesn't have to be the URI to a real, existing site.
App is working but with following problems:
(it can't add tasks on behalf of other users though)
(UPDATE 11/7: this might've been a problem that existed in the original forked repo)
2. Tasks have correct owners when a new user creates an account and log in, but wrong owners if an existing user logs in; however, refreshing the page corrects the problem. (Still trying to figure out what went wrong as the front end is getting the right data.)
(UPDATE 11/7: new bug introduced)
3. A user making a new account with an existing email should trigger an error message saying there's an existing user with that email--the error message is sent to the browser but not displayed for some reason.
After fixing these two issues, the next steps are:
Please feel free to suggest other services to use, other ways to doing things, and best practices in general for app building.