{"id":15549798,"url":"https://github.com/iturres/notes-web-app","last_synced_at":"2025-04-23T19:22:38.325Z","repository":{"id":151862243,"uuid":"624981711","full_name":"ITurres/Notes-Web-App","owner":"ITurres","description":"📝 \"Notes\" is a fundamental web application that shares similarities with iCloud's 'Notes,' enabling users to create an account, sign in, and seamlessly manage their notes by creating, updating, and deleting them and search specific notes based on their content.","archived":false,"fork":false,"pushed_at":"2023-12-10T02:28:21.000Z","size":88414,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-09T10:42:50.274Z","etag":null,"topics":["cs50x","flask","harvard","inotes","javascript","python3","sqlite3"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ITurres.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-04-07T18:48:35.000Z","updated_at":"2023-08-22T22:54:22.000Z","dependencies_parsed_at":"2023-05-13T05:15:08.726Z","dependency_job_id":null,"html_url":"https://github.com/ITurres/Notes-Web-App","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ITurres%2FNotes-Web-App","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ITurres%2FNotes-Web-App/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ITurres%2FNotes-Web-App/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ITurres%2FNotes-Web-App/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ITurres","download_url":"https://codeload.github.com/ITurres/Notes-Web-App/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235208997,"owners_count":18953003,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cs50x","flask","harvard","inotes","javascript","python3","sqlite3"],"created_at":"2024-10-02T13:41:39.026Z","updated_at":"2025-01-23T00:55:31.943Z","avatar_url":"https://github.com/ITurres.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n    \u003cimg alt=\"notes website logo\" src=\"readme-src/readme-media/notes-logo.png\" width=\"100\"\u003e\n    \u003ch1\u003eNotes\u003c/h1\u003e\n\u003c/div\u003e\n\n\u003e “Notes” is my cs50x final project Web Application. It is a basic web app that resembles a bit like 'Notes' from iCloud, and where you can create an account, sign in and start creating, updating, and deleting your notes, plus search for specific ones given their content.\n\n#### Project Presentation (Video Demo): \u003chttps://youtu.be/UJucGYwoDCA\u003e\n\n---\n\n#### **\\*Previews at the end of this file.**\n\n---\n\n## Built With\n\n- HTML - HTML5\n- CSS - CSS3\n- JavaScript\n- Python 3\n- Flask\n- cs50 for SQL\n- sqlite\n\n#### [![My Skills](https://skillicons.dev/icons?i=html,css,js,python,flask,sqlite)](https://skillicons.dev)\n\n---\n\n\u003cbr\u003e\n\n## [![My Skills](https://skillicons.dev/icons?i=python)](https://skillicons.dev) Understanding .py files\n\n## **\u003e app.py**\n\n\u003e It is the engine of the website, where all the data manipulation, queries to the database and the rendering of each webpage happens.\n\n### There are 8 main functions, all link to it's specific and individual route. (list below)\n\n- index\n- login\n- logout\n- register\n- add_new_note\n- update_note\n- delete_note\n- search_notes\n\n- ### Note: ( index, add_new_note, update_note, delete_note and search_notes ) make use of @helpers.login_required (see helpers.py \\*Understanding section)\n\n### **\u003e\u003e index():**\n\n\u003e index will only be executed as long as @helpers.login_required has return correctly.\n\u003e This function routes you to the main/home/index webpage which only you (the user, if and only if has been successfully logged in) can access. And\n\u003e where through a SQL query the function will render the said main/home/index webpage with the user's data (name, notes).\n\n### **\u003e\u003e login():**\n\n\u003e The login function, makes sure to first clean the current session and then process the data provided through the POST method to validate it.\n\u003e Login makes sure the 'user' enters valid data, such as username and password. It checks whether it's not empty if it is correct, and if it matches the data\n\u003e in the database or not. Again this last one uses an SQLite query.\n\n\u003e When a validation error occurs, the function will return by rendering the webpage again, keeping the 'user's input values in place and showing to\n\u003e the user, what's wrong with the input value.\n\n\u003e If the 'user' has successfully logged in, then the index.html webpage will be rendered and a -flash- message will be shown to the 'user'.\n\n### **\u003e\u003e logout():**\n\n\u003e The logout function just clear the current 'user' session and return by rendering to index, which in consequence, will redirect to login.\n\n### **\u003e\u003e register():**\n\n\u003e register, as the word says, will 'register' the new user. It again will process the data provided through the POST method to validate it.\n\u003e register will make sure the 'user' enters valid data, such as username, password, and password confirmation. It checks whether it's not empty if it is correct, and in the case of the password, if both the password and the confirmation match.\n\u003e Then it will insert all the validated data into the -'users'- database (see notes.db \\*Understanding section).\n\u003e next it will query all data from the 'user', and store it in a variable to SET the current -session- with the 'user''s id\n\u003e afterwards will return by rendering index (/) and flash the user a \"successfully register\" message with the 'user''s name.\n\n### **\u003e\u003e add_new_note():**\n\n\u003e This function when the request method is POST will first store the current session id in a variable, then validate the new note content (if it is empty or not)\n\u003e and will insert into the user_notes table in the database (see notes.db \\*Understanding section) the note content where the 'user''s id matches.\n\u003e then will return by redirecting to index (/).\n\n### **\u003e\u003e update_note():**\n\n\u003e update_note behaves like add_new_note, except that this function will query to update the column note_content if the note_id matches.\n\u003e The function will store the note content into a variable as well as the note's id and then proceeds to query the update.\n\u003e Finally, the function will return by redirecting to index (/).\n\n### **\u003e\u003e delete_note():**\n\n\u003e The delete_note function when the request method is POST, will store the selected note's id and query the deletion to the note that matches the given id.\n\u003e Finally, the function will return by redirecting to index (/).\n\n### **\u003e\u003e search_notes():**\n\n\u003e If the request method is POST, the function will store the current session id, and it will get the value from the input to be searched.\n\u003e This value (value_searched) will be concatenated with two % (percentage symbols) to insert it into the later query.\n\u003e Then the function will query for a list of all the notes found that match the current user id and the value_searched.\n\u003e Later it will store the length of that list (as the number of notes found, AKA results) and lastly, it will return by rendering\n\u003e search-results.html and passing results and the list (notes_found) to the html file.\n\n---\n\n## \u003e helpers.py\n\n\u003e This file contains all the sub-functions used in app.py such as login_required and check_username.\n\n### **\u003e\u003e login_required(f):**\n\n\u003e f (the parameter passed to login_required) will be the function to be wrapped. login_required returns the wrapped function. This is done by creating an inner function and returning it.\n\u003e Note that the first two returns are part of decorated_function (the inner function, not invoked in this code, just defined), while the third one is part of \u003e\n\u003e login_required.\n\u003e decorated_function is a function returned by login_required (it's another function object every time login_required is called). That function will be used\n\u003e instead of the one passed for f. So every time one would call index function, the call would go to the function returned by login_required(index) instead.\n\u003e And here is the documentation on \u003ca href=\"https://docs.python.org/3/library/functools.html#functools.wraps\"\u003e@wraps\u003c/a\u003e\n\u003e =\u003e credits to \u003ca href=\"https://www.reddit.com/r/cs50/comments/ac6678/which_is_the_explanation_of_how_the_custom/\"\u003eBlauelf\u003c/a\u003e.\n\n### **\u003e\u003e check_username(username):**\n\n\u003e This function will query the users table in the notes database to retrieve the username that matches the username passed as a parameter\n\u003e then it will check whether the query successfully retrieves any data or not, and return said result as a boolean (true/false).\n\n---\n\n## [![My Skills](https://skillicons.dev/icons?i=sqlite)](https://skillicons.dev) Understanding .db files\n\n## \u003e notes.db\n\n\u003e notes database is the main database, which holds four tables:\n\n- 1: **users**, Which itself holds three columns =\u003e id (primary-key), username, hash. The last one is used as the password.\n- 2: **user_notes**, which holds five columns =\u003e id (primary-key), user_id, note_content, date_time, and a reference to foreign key.\n- 3: **sqlite_sequence**, the table automatically created by app.config.\n- 4: and a UNIQUE INDEX table for username on **users** (1:).\n\n\u003e for a more graphical peek, have a look at the =\u003e notes-db-template.db -file-.\n\n---\n\n## [![My Skills](https://skillicons.dev/icons?i=js)](https://skillicons.dev) Understanding .js files within /animations folder\n\n## \u003e toggle-note-height.js\n\n\u003e The variable -noteTextarea- gets the element that has the data attribute indicated within [] square-brackets.\n\u003e then within a loop it listen for a click and as a result of it, this toggles two classes:\n\n- 1: **large** =\u003e that apply a specific (height) to the element targeted, see folder animations/expand-note.css.\n- 2: **hidden** =\u003e this last one is apply to the two times sibling's element, and it toggles the property (display) and (visibility).\n  \u003e see folder animations/toggle-visibility.css.\n\n## \u003e toggle-visibility.js\n\n\u003e There are two variables, -newNoteForm- and -toggleNewNoteFormBtn-, each gets the element that has the data attribute indicated\n\u003e within [] square-brackets.\n\n\u003e -toggleNewNoteFormBtn- is a collection of HTML elements, and on line 13 is associated with a forEach loop method that for each\n\u003e element it listens for a click (through an event listener) and calls the function -toggleHiddenClass()- (described next) passing as parameters the\n\u003e variable -newNoteForm- and -toggleNewNoteFormBtn- itself.\n\n### **\u003e\u003e toggleHiddenClass(elements, element):**\n\n\u003e This function takes -elements- (a collection of HTML elements) and -element- (a single HTML element) as parameters.\n\u003e Within the function, it loops through -elements- with the \"forEach\" method, and for each element it toggles the element's class -hidden-.\n\u003e Finally, -element- also gets its class toggled.\n\n---\n\n\u003cbr\u003e\n\n## Previews\n\n### **\\* There are 7 short previews, each showing the following actions:**\n\n- register\n- add_new_note\n- update_note\n- delete_note\n- search_notes\n- login\n- logout\n\n### **register:**\n\n\u003chttps://user-images.githubusercontent.com/100724715/230662591-87498795-1d2b-415e-8cb8-f682405120ed.mp4\u003e\n\n### **add_new_note:**\n\n\u003chttps://user-images.githubusercontent.com/100724715/230662636-0a9fec94-2a69-43ae-970a-7901f072a374.mp4\u003e\n\n### **update_note:**\n\n\u003chttps://user-images.githubusercontent.com/100724715/230662651-2ad322fe-aa22-4140-be2c-0d8b8a470bac.mp4\u003e\n\n### **delete_note:**\n\n\u003chttps://user-images.githubusercontent.com/100724715/230662667-50784120-08a7-43b2-95e8-c26b87cf7427.mp4\u003e\n\n### **search_notes:**\n\n\u003chttps://user-images.githubusercontent.com/100724715/230662677-2c397567-151a-4546-abf6-ce229ce8c8e8.mp4\u003e\n\n### **login:**\n\n\u003chttps://user-images.githubusercontent.com/100724715/230662689-71edc721-9ae9-4c8e-995c-d1291c10382e.mp4\u003e\n\n### **logout:**\n\n\u003chttps://user-images.githubusercontent.com/100724715/230662696-86e595d4-45cf-4121-bee9-3fc981db2037.mp4\u003e\n\n---\n\n## Author\n\n### 🙋‍♂️ Arthur Iturres\n\n- #### [![My Skills](https://skillicons.dev/icons?i=github)](https://skillicons.dev) [@ITurres](https://github.com/ITurres)\n\n- #### [![My Skills](https://skillicons.dev/icons?i=linkedin)](https://skillicons.dev) [Linkedin](https://www.linkedin.com/in/arturoemanuelguerraiturres/)\n\n---\n\n## Show your support\n\n#### Give a ⭐ if you liked this project\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiturres%2Fnotes-web-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fiturres%2Fnotes-web-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiturres%2Fnotes-web-app/lists"}