somethinggeneric / flaskpress Goto Github PK
View Code? Open in Web Editor NEWWordpress but it's actually Python + Flask
License: GNU General Public License v3.0
Wordpress but it's actually Python + Flask
License: GNU General Public License v3.0
Parent issue: #13
templates/profile.html
• Create a basic HTML structure with placeholders for the user's profile information.
• Add a section to display the user's username.
• Add a section to display the user's posts.
main.py
• Refactor the post() function to check the request method.
• If the request method is GET, return all posts.
• If the request method is POST, handle the creation of a new post as currently implemented.
Parent issue: #13
templates/home.html
• Create a basic layout for the home page. This can include a header with the website's name, a navigation bar, and a main content area.
templates/login.html
• Create a form for users to input their login credentials. The form should have fields for username and password, and a submit button.
templates/register.html
• Create a form for users to input their registration details. The form should have fields for username, email, password, confirm password, and a submit button.
Parent issue: #13
main.py
• In the login() function, add a check for if the request method is POST.
• If the request method is POST, retrieve the username and password from the form data.
• Validate these credentials against the database. If they are valid, use Flask-Login's login_user() function to log the user in and redirect them to the home page.
• If the credentials are not valid, flash an error message and render the login template again.
• In the signup() function, add a check for if the request method is POST.
• If the request method is POST, retrieve the username and password from the form data.
• Validate this input to ensure the username is not already taken and the password meets any necessary requirements.
• If the input is valid, create a new User object and add it to the database. Then log the user in and redirect them to the home page.
• If the input is not valid, flash an error message and render the signup template again.
My goal for this project is a system similar to Wordpress but it's written in Python + Flask.
Please define some of the basic routes, and set up the framework for a main python file, and a requirements.txt as needed
main.py
• Create a new Flask application.
• Set up Flask-Login by creating a User model with fields for username and password.
• Define routes for login, logout, and signup. Handle user sessions using Flask-Login.
• Define basic routes for the application, such as the homepage, user profile pages, and a page for creating new posts.
• Handle errors appropriately in your routes and protect routes that should only be accessible to authenticated users.
requirements.txt
• Add Flask, Flask-Login, and an asynchronous library for Flask to the list of requirements.
site.db
in the working directory.Parent issue: #13
templates/blank.html
• Create a basic HTML structure that includes the doctype declaration, html, head, and body tags.
• Inside the body tag, add a block content directive ({% block content %}{% endblock %}
) that will be used to insert the content of the requested page.
main.py
• Change the SQLite connection from
sqlite:////tmp/test.db
tosqlite:///site.db
on line 8.
Ideally, the code will load pages from a directory, maybe "pages/", and render them using mistune, to return at a dynamically-named flask endpoint.
requirements.txt
• Add Mistune to the list of required packages.
main.py
• Import os and mistune at the top of the file.
• Create a new function namedload_and_parse_md
that takes a filename as an argument. This function should use os to load the file from the "pages/" directory and Mistune to parse the markdown content into HTML.
• Create a new Flask route that takes a filename as a dynamic part of the route. This route should call theload_and_parse_md
function with the filename and return the resulting HTML.
tests/test_main.py
• Import pytest, flask, and the main module at the top of the file.
• Write a test function namedtest_load_and_parse_md
that tests theload_and_parse_md
function. This test should check that the function correctly loads and parses a markdown file.
• Write a test function namedtest_dynamic_route
that tests the new dynamic route. This test should check that the route correctly serves the parsed markdown content.
Ideally a page with a text editor so that markdown content can be created, then it will redirect to the POST endpoint which submits the new post to the server.
And an appropriate GET endpoint to serve up this page to the user, if they're signed in.
templates/create_page.html
• Add a form with a text editor field for users to write their content in markdown.
• Add a submit button to the form that posts the form data to the new POST endpoint.
main.py
• Add a new GET endpoint that serves the
create_page.html
page to the user if they are signed in.
• Add a new POST endpoint that handles the submission of the new page content from the form increate_page.html
.
• In the GET endpoint, add a check to verify if the user is signed in before serving thecreate_page.html
page.
Parent issue: #13
templates/profile.html
• Add a new section to display the user's username. This can be done by adding a new 'h2' tag and using the 'user.username' variable to display the username.
• Add a new section to display the user's email. This can be done by adding a new 'p' tag and using the 'user.email' variable to display the email.
• Add a new section to display the user's posts. This can be done by adding a new 'section' tag and using a 'for' loop to iterate over the 'user.posts' variable. For each post, add an 'article' tag and use the 'post.title' and 'post.content' variables to display the post's title and content.
Parent issue: #13
main.py
• Refactor the post() function to handle GET and POST requests separately. Use the request.method attribute to determine the type of the request.
• For GET requests, read all the files in the 'pages' directory and return their content. Use the os.listdir() function to get a list of all files in the directory, and then use a loop to read each file and append its content to a list. Finally, return this list.
• For POST requests, get the post data from the request using the request.form.get() function. Write this data to a new file in the 'pages' directory using the open() function with the 'w' mode. Then, redirect to the new post's page using the redirect() function and the url_for() function.
• Before attempting to read from or write to the 'pages' directory, check if the directory exists using the os.path.exists() function. If it does not exist, create it using the os.makedirs() function.
Parent issue: #13
templates/profile.html
• Add a new section after the username section to display additional user information.
• In the new section, add a line to display the user's email. Use the variable user.email to get the email of the user.
• Add another line to display the date the user joined. Use the variable user.date_joined to get the date the user joined.
• Add a final line to display the number of posts the user has made. Use the len function on the user.posts variable to get the number of posts.
In line 47 of main.py
, handle an incoming post request with a markdown text attribute, and save to an appropriate file name under the (presumed) pages/
directory, so that the /pages
endpoint can then load it. Ideally, return a redirect to the appropriate /pages/
endpoint.
main.py
• Modify the
post()
function to extract the markdown text from the incoming POST request. You can access the markdown text usingrequest.form.get('markdown')
.
• In thepost()
function, generate a unique filename for the new post. One way to do this is to use the current timestamp, like so:filename = f"{time.time()}.md"
.
• Still in thepost()
function, check if thepages/
directory exists. If it does not, create it usingos.makedirs('pages')
.
• Next, in thepost()
function, open a new file in thepages/
directory with the generated filename and write the markdown text to it.
• Finally, modify thepost()
function to return a redirect to the new post's page. You can do this withreturn redirect(url_for('page', filename=filename))
.
blank.html
with a basic layout that can be filled in with the content of the requested page.Parent issue: #13
templates/blank.html
• Add the doctype declaration for HTML5 at the top of the file.
• Add the opening and closing HTML tags.
• Inside the HTML tags, add the opening and closing head tags.
• Inside the head tags, add the meta charset declaration for UTF-8.
• Still inside the head tags, add the meta viewport tag with the content attribute set to "width=device-width, initial-scale=1.0".
• Still inside the head tags, add the title tag with the content "FlaskPress".
• After the head tags, add the opening and closing body tags.
• Inside the body tags, add the opening and closing tags for a block named "content".
When registration is attempted through the endpoint on line 62 of main.py
, SQAlchemy throws an error becauase the database hasn't been set up for users.
More of the error message:
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: user
[SQL: SELECT user.id AS user_id, user.username AS user_username, user.password AS user_password
FROM user
WHERE user.username = ?
LIMIT ? OFFSET ?]
[parameters: ('foo', 1, 0)]
(Background on this error at: https://sqlalche.me/e/20/e3q8)
Possibly helpful: https://docs.sqlalchemy.org/en/20/errors.html#error-e3q8
The error might also be related to the implementation of the UserMixin?
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(30), unique=True)
password = db.Column(db.String(30))
The line that specifically triggers the error is
user = User.query.filter_by(username=username).first()
Parent issue: #13
templates/blank.html
• Add the opening and closing html tags.
• Inside the html tags, add the opening and closing head tags.
• Inside the head tags, add a title tag with the text "Blank Template".
• After the head tags, add the opening and closing body tags.
• Inside the body tags, add a comment that says "Page content goes here".
Parent issue: #13
main.py
• Replace the current SQLite connection string in the app.config["SQLALCHEMY_DATABASE_URI"] with 'sqlite:///site.db'.
Parent issue: #13
templates/profile.html
• Add a new section to display the user's email. Use Jinja2 syntax to dynamically display the user's email. This can be done by adding a new section with a heading of "Email" and a paragraph with the content "{{ user.email }}".
• Add a new section to display the user's date of registration. Use Jinja2 syntax to dynamically display the user's date of registration. This can be done by adding a new section with a heading of "Date of Registration" and a paragraph with the content "{{ user.date_of_registration }}".
• Add a placeholder for the user's profile picture. This can be done by adding an img tag with a src attribute of "{{ user.profile_picture_url }}". Note that this assumes that the user object has a profile_picture_url attribute that contains the URL of the user's profile picture.
Parent issue: #13
main.py
• Refactor the post() function to handle GET and POST requests separately. Use the request.method attribute to determine the type of the request.
• For the GET method, read all the files in the 'pages' directory and return their content. Use the os.listdir() function to get the list of files and the open() function in a loop to read their content.
• For the POST method, get the filename and markdown content from the request using the request.form.get() function. Write the content to a new file in the 'pages' directory using the open() function with the 'w' mode. After writing the content, redirect to the new page using the redirect() function and the url_for() function.
Implement a method similar to the one described in https://flask-login.readthedocs.io/en/latest/#how-it-works
So that Flask-Login will function correctly.
main.py
• Add a new function named load_user that takes user_id as an argument. This function should query the database for a user with the given user_id and return the user object if it exists.
• Decorate the load_user function with @login_manager.user_loader to register it as a user loader function.
Ideally, the code formatter, if it changes files, should then open a pull request to submit back the formatted code as a PR. This can be after the tests are run.
.github/workflows/test.yml
• Add a new step after the Black code formatting step. This step should run a script that checks if there are any modified files using the git status command.
• If there are modified files, the script should commit these changes with a descriptive commit message.
• The script should then create a new pull request against the main branch using the GitHub CLI or the GitHub API. The title and body of the pull request should clearly indicate that it contains code formatting changes.
site.db
in the working directory.Parent issue: #13
site.db
in the working directory.Parent issue: #13
main.py
• Change the SQLite connection string from
sqlite:///site.db
tosite.db
in the Flask application configuration.
Ideally also rename existing targets to make a more sensible make
-flow
Makefile
• Add a new target named
update-packages
that runs the commandpip install --upgrade -r requirements.txt
.
Parent issue: #13
main.py
• Separate the logic for the GET and POST methods in the post() function using an if-else statement. The if statement should check if the request method is 'GET', and the else statement should handle the 'POST' method.
• In the if statement for the 'GET' method, fetch all posts from the 'pages' directory and return them. This can be done by iterating over all files in the 'pages' directory, reading the content of each file, and appending it to a list of posts. Then, render the 'posts.html' template with the list of posts.
• In the else statement for the 'POST' method, get the filename and markdown content from the request. If the filename is not provided, generate a filename using the current time. Then, write the markdown content to a new file in the 'pages' directory with the given filename. Finally, redirect to the new page using the url_for() function with 'page' as the endpoint and the filename as a parameter.
When registration is attempted through the endpoint on line 62 of main.py
, SQAlchemy throws an error becauase the database hasn't been set up for users.
More of the error message:
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: user
[SQL: SELECT user.id AS user_id, user.username AS user_username, user.password AS user_password
FROM user
WHERE user.username = ?
LIMIT ? OFFSET ?]
[parameters: ('foo', 1, 0)]
(Background on this error at: https://sqlalche.me/e/20/e3q8)
Possibly helpful: https://docs.sqlalchemy.org/en/20/errors.html#error-e3q8
The error might also be related to the implementation of the UserMixin?
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(30), unique=True)
password = db.Column(db.String(30))
The line that specifically triggers the error is
user = User.query.filter_by(username=username).first()
profile.html
for the related endpoint.blank.html
to be filled in by the /page/<name>
enpoint.site.db
in the working directory.Checklist:
Implement home and login/registration page templates
- In home.html, create a basic layout for the home page.
- In login.html, create a form for users to input their login credentials.
- In register.html, create a form for users to input their registration details.
Handle login and registration POST requests
- In main.py, update the login() function to handle POST requests and validate user input.
- In main.py, update the signup() function to handle POST requests, validate user input, and update the database.
Create profile template and refactor new post method
- In profile.html, create a basic layout to display the user's profile information.
- In main.py, refactor the post() function to return all posts on GET and handle a new post on POST.
Implement blank template and change SQLite connection
- In blank.html, create a basic layout that can be filled in with the content of the requested page.
- In main.py, change the SQLite connection to
site.db
in the working directory.
Checklist:
Create profile template
- In templates/profile.html, create a basic layout to display the user's profile information.
Refactor new post method
- In main.py, refactor the post() function to return all posts on GET and handle a new post on POST.
Change SQLite connection
- In main.py, change the SQLite connection to
site.db
in the working directory.
site.db
in the working directory.Parent issue: #13
main.py
• Import the os module at the top of the file, if it's not already imported.
• Replace the lineapp.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///site.db"
withapp.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///" + os.path.join(os.getcwd(), "site.db")
.
draw an ascii cat in README.md
Make a new markdown file and describe each flask endpoint in the markdown file. Try to infer what each endpoint's docstrings should be.
The github action should use some linux runner, and setup the app with pip, and at the very least, it should format the code.
Ideally, it would also use some kind of unittest for the flask code, and some framework to test the responses of api endpoints.
.github/workflows/test.yml
• Start the workflow file with a name and specify when it should run (e.g., on every push and pull request).
• Add a job that runs on an Ubuntu-latest runner.
• In the job, add a step to check out the code using the actions/checkout@v2 action.
• Add a step to set up Python 3.11 using the actions/setup-python@v2 action.
• Add a step to install dependencies using pip. This step should run "pip install -r requirements.txt".
• Add a step to format the code using Black. This step should run "black .".
• Add a step to run unit tests. This step should run "python -m unittest".
tests/test_main.py
• Ensure that the test file can be run as a module by adding a check for name == "main" at the end of the file.
• Inside the check, call unittest.main() to run the tests.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.