diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..1e5d77c --- /dev/null +++ b/.flake8 @@ -0,0 +1,12 @@ +[flake8] +max-line-length = 120 +exclude= + migrations + mysite + logs + .venv + apps.py + setup.py +per-file-ignores = + .\polls\tests\test_sentiment_model.py: E501 + .\polls\models.py: F811 \ No newline at end of file diff --git a/Installation.md b/Installation.md new file mode 100644 index 0000000..da70d2e --- /dev/null +++ b/Installation.md @@ -0,0 +1,97 @@ +## Installation + +There are two ways to install and run this project. + +1. Use `setup.py` or `setup.ps1`(for windows) to install the project. +2. Manually install the project with the Instruction in section 2. + +### 1. Use `setup.py` or `setup.ps1`(for windows) to install the project. +1. Install [Python 3.11 or later](https://www.python.org/downloads/) +2. Clone this repository and Run `setup.py` to install and run the project + +**Don't forget to answer the question from `setup.py` to setup the project** + +This method will autogenerate Environment Variable for you. +```bash +git clone https://github.com/Sosokker/ku-polls +cd ku-polls +python setup.py +``` +If you want to customize the environment variables, name of environment folder then run this command +```bash +python setup.py -custom +``` +or run `setup.ps1` (For Windows User) + +---- + +### 2. Manually install the project with this instruction. + +1. Install [Python 3.11 or later](https://www.python.org/downloads/) +2. Run these commands to clone this repository and enter the directory. +```bash +git clone https://github.com/Sosokker/ku-polls +cd ku +``` + +3. (Optional: You can use venv instead)Install virtualenv via pip + +```bash +python -m pip install --user virtualenv +``` +4. Create virtual environment with `venv` or `virtualenv`. +```bash +python -m virtualenv .venv +or +python -m venv .venv +``` +5. Use `virtual environment` + +- Windows +```bash +.venv\Scripts\activate +``` + +- Linux or MacOS +```bash +source .venv/bin/activate +``` +6. Install require module. +``` +pip install -r requirements.txt +``` + +7. Create file call `.env` in `ku-polls` directory and add this line +**You can look at `sample.env` for more information and others environment variables to set.** +```bash +SECRET_KEY=your_secret_key +``` + +You can generate your own `your_secret_key` by this command +```bash +python manage.py shell -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())" +``` +or +- [Django Secret Key Generator #1](https://djecrety.ir/) +- [Django Secret Key Generator #2](https://miniwebtool.com/django-secret-key-generator/) + +**Don't forget to change `your_secret_key` to your secret key (without quote)** + +8. Migrate database and load data into it then runserver. +```bash +python manage.py migrate +python manage.py loaddata data/users.json +python manage.py loaddata data/polls.json +python manage.py runserver +``` + +***NOTE*** + +By Default `DEBUG=False` and Django will not load Static files for you so if you want to apply CSS run this. +```bash +python manage.py runserver --insecure +``` +or set `DEBUG=True` +or do the [collectstatic](https://docs.djangoproject.com/en/4.2/ref/contrib/staticfiles/) + +Then connect to [http://127.0.0.1:8000/](http://127.0.0.1:8000/) or [localhost:8000/](localhost:8000/) diff --git a/data/alldata.json b/data/alldata.json new file mode 100644 index 0000000..8c4f83b --- /dev/null +++ b/data/alldata.json @@ -0,0 +1,1265 @@ +[ +{ + "model": "polls.tag", + "pk": 4, + "fields": { + "tag_text": "Food" + } +}, +{ + "model": "polls.tag", + "pk": 5, + "fields": { + "tag_text": "Flirt" + } +}, +{ + "model": "polls.tag", + "pk": 6, + "fields": { + "tag_text": "Meme" + } +}, +{ + "model": "polls.tag", + "pk": 7, + "fields": { + "tag_text": "Programming" + } +}, +{ + "model": "polls.tag", + "pk": 8, + "fields": { + "tag_text": "Singer" + } +}, +{ + "model": "polls.tag", + "pk": 9, + "fields": { + "tag_text": "Education" + } +}, +{ + "model": "polls.question", + "pk": 1, + "fields": { + "question_text": "Python vs C++, which one is better in your opinion?", + "pub_date": "2023-09-11T06:31:14Z", + "end_date": "2023-09-29T20:31:49Z", + "short_description": "🐍 vs πŸ‡¨ ++", + "long_description": "Let them fight.", + "trend_score": 60.0, + "tags": [ + 7 + ] + } +}, +{ + "model": "polls.question", + "pk": 2, + "fields": { + "question_text": "The chicken and the egg, which came first?", + "pub_date": "2023-09-11T02:50:04Z", + "end_date": "2023-10-18T23:50:19Z", + "short_description": "Classic question.", + "long_description": "Most biologists state unequivocally that the egg came first. At their most basic level, eggs are just female sex cells. Hard external eggs that can be laid on land (also known as amniotic eggs) were a game changer for vertebrates. Anyway, let select you choice.", + "trend_score": 140.0, + "tags": [ + 4 + ] + } +}, +{ + "model": "polls.question", + "pk": 3, + "fields": { + "question_text": "So far so good?", + "pub_date": "2023-08-03T06:50:43Z", + "end_date": "2023-11-28T19:50:53Z", + "short_description": "If you know, you know.", + "long_description": "The sentence where you will hear once every week.", + "trend_score": 120.0, + "tags": [ + 6 + ] + } +}, +{ + "model": "polls.question", + "pk": 4, + "fields": { + "question_text": "Do you love Django?", + "pub_date": "2023-09-11T19:51:12Z", + "end_date": "2023-09-29T17:51:18Z", + "short_description": "Djago, I love it!", + "long_description": "Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. Built by experienced developers, it takes care of much of the hassle of web development, so you can focus on writing your app without needing to reinvent the wheel. It’s free and open source.", + "trend_score": 120.0, + "tags": [ + 7 + ] + } +}, +{ + "model": "polls.question", + "pk": 6, + "fields": { + "question_text": "Taylor Swift vs Kanye West. Who is better!", + "pub_date": "2023-09-15T15:46:58Z", + "end_date": "2023-11-30T15:47:01Z", + "short_description": "Swifty vs Ye Club", + "long_description": "It's no secret that Taylor Swift and Kanye West's relationship can be described as volatile at best. Let choose!", + "trend_score": 100.0, + "tags": [ + 8 + ] + } +}, +{ + "model": "polls.question", + "pk": 7, + "fields": { + "question_text": "What is your preferred text editor or IDE for coding?", + "pub_date": "2023-09-15T15:49:22Z", + "end_date": "2023-11-21T23:00:00Z", + "short_description": "Please do my pollπŸ₯Ί", + "long_description": "My favorite code editor is VScode. What about you?", + "trend_score": 100.0, + "tags": [ + 7 + ] + } +}, +{ + "model": "polls.question", + "pk": 8, + "fields": { + "question_text": "Which one is the best RIZZ line?", + "pub_date": "2023-09-17T16:39:52Z", + "end_date": "2023-12-12T17:00:00Z", + "short_description": "RIZZ (noun) How good you are with flirting", + "long_description": "Rizz actually comes from the word charisma. It's a NYC Slang created by a twitch streamer named Kai cenat. This means that you have game, a good flirt line.", + "trend_score": 100.0, + "tags": [ + 5, + 6 + ] + } +}, +{ + "model": "polls.question", + "pk": 9, + "fields": { + "question_text": "What is the best pizza topping?", + "pub_date": "2023-09-15T16:10:02Z", + "end_date": "2023-12-31T05:00:00Z", + "short_description": "Pizza without topping is not pizza!", + "long_description": "I mean, Yeah here are the choices ;)", + "trend_score": 100.0, + "tags": [ + 4 + ] + } +}, +{ + "model": "polls.question", + "pk": 14, + "fields": { + "question_text": "What is your favorite subjects?", + "pub_date": "2023-09-17T16:37:49Z", + "end_date": "2023-11-29T16:37:53Z", + "short_description": "Which subjects do you love?", + "long_description": "Here are the list of subjects, which one is the best for you!", + "trend_score": 100.0, + "tags": [ + 9 + ] + } +}, +{ + "model": "polls.choice", + "pk": 1, + "fields": { + "question": 1, + "choice_text": "C++" + } +}, +{ + "model": "polls.choice", + "pk": 2, + "fields": { + "question": 1, + "choice_text": "Python" + } +}, +{ + "model": "polls.choice", + "pk": 3, + "fields": { + "question": 2, + "choice_text": "Egg!" + } +}, +{ + "model": "polls.choice", + "pk": 4, + "fields": { + "question": 2, + "choice_text": "Chicken" + } +}, +{ + "model": "polls.choice", + "pk": 5, + "fields": { + "question": 3, + "choice_text": "Yes sir!" + } +}, +{ + "model": "polls.choice", + "pk": 6, + "fields": { + "question": 3, + "choice_text": "Nah" + } +}, +{ + "model": "polls.choice", + "pk": 7, + "fields": { + "question": 4, + "choice_text": "Yeah for sure!" + } +}, +{ + "model": "polls.choice", + "pk": 8, + "fields": { + "question": 4, + "choice_text": "Hell nah!" + } +}, +{ + "model": "polls.choice", + "pk": 9, + "fields": { + "question": 4, + "choice_text": "No comment." + } +}, +{ + "model": "polls.choice", + "pk": 10, + "fields": { + "question": 6, + "choice_text": "Kanye" + } +}, +{ + "model": "polls.choice", + "pk": 11, + "fields": { + "question": 6, + "choice_text": "Taylor Swift" + } +}, +{ + "model": "polls.choice", + "pk": 12, + "fields": { + "question": 6, + "choice_text": "Nobody is better than others." + } +}, +{ + "model": "polls.choice", + "pk": 13, + "fields": { + "question": 6, + "choice_text": "Both!" + } +}, +{ + "model": "polls.choice", + "pk": 14, + "fields": { + "question": 6, + "choice_text": "No Opinion" + } +}, +{ + "model": "polls.choice", + "pk": 15, + "fields": { + "question": 7, + "choice_text": "VScode" + } +}, +{ + "model": "polls.choice", + "pk": 16, + "fields": { + "question": 7, + "choice_text": "JetBrains IDE" + } +}, +{ + "model": "polls.choice", + "pk": 17, + "fields": { + "question": 7, + "choice_text": "Vim" + } +}, +{ + "model": "polls.choice", + "pk": 18, + "fields": { + "question": 7, + "choice_text": "Emacs" + } +}, +{ + "model": "polls.choice", + "pk": 19, + "fields": { + "question": 7, + "choice_text": "Eclipse" + } +}, +{ + "model": "polls.choice", + "pk": 20, + "fields": { + "question": 8, + "choice_text": "Let me be your CSS to your HTML" + } +}, +{ + "model": "polls.choice", + "pk": 21, + "fields": { + "question": 8, + "choice_text": "Are you my grade? Because Im nervous everytime Im about to see you" + } +}, +{ + "model": "polls.choice", + "pk": 22, + "fields": { + "question": 8, + "choice_text": "If being beautiful was a crime, you’d be on the most wanted list." + } +}, +{ + "model": "polls.choice", + "pk": 23, + "fields": { + "question": 8, + "choice_text": "You look like mom! Mom of our son." + } +}, +{ + "model": "polls.choice", + "pk": 24, + "fields": { + "question": 8, + "choice_text": "Are you from Tennessee cuz u the only ten I see" + } +}, +{ + "model": "polls.choice", + "pk": 25, + "fields": { + "question": 8, + "choice_text": "Ouch i skinned my knee! because I fall for you" + } +}, +{ + "model": "polls.choice", + "pk": 26, + "fields": { + "question": 8, + "choice_text": "Are you semicolon!! cause you alway make me complete." + } +}, +{ + "model": "polls.choice", + "pk": 27, + "fields": { + "question": 8, + "choice_text": "Roses are red, Violets are blue, Something smells is that you!" + } +}, +{ + "model": "polls.choice", + "pk": 28, + "fields": { + "question": 9, + "choice_text": "Pineapples" + } +}, +{ + "model": "polls.choice", + "pk": 29, + "fields": { + "question": 9, + "choice_text": "Orange" + } +}, +{ + "model": "polls.choice", + "pk": 30, + "fields": { + "question": 9, + "choice_text": "Banana" + } +}, +{ + "model": "polls.choice", + "pk": 31, + "fields": { + "question": 8, + "choice_text": "What is the difference betweeen history and you? History is in the past but you are my future." + } +}, +{ + "model": "polls.choice", + "pk": 32, + "fields": { + "question": 1, + "choice_text": "Use both!" + } +}, +{ + "model": "polls.choice", + "pk": 33, + "fields": { + "question": 2, + "choice_text": "Dinosaur" + } +}, +{ + "model": "polls.choice", + "pk": 38, + "fields": { + "question": 9, + "choice_text": "Pepperoni" + } +}, +{ + "model": "polls.choice", + "pk": 39, + "fields": { + "question": 9, + "choice_text": "Chicken breast" + } +}, +{ + "model": "polls.choice", + "pk": 40, + "fields": { + "question": 9, + "choice_text": "Mushrooms" + } +}, +{ + "model": "polls.choice", + "pk": 41, + "fields": { + "question": 9, + "choice_text": "Tomato" + } +}, +{ + "model": "polls.choice", + "pk": 42, + "fields": { + "question": 9, + "choice_text": "Onions" + } +}, +{ + "model": "polls.choice", + "pk": 43, + "fields": { + "question": 7, + "choice_text": "Sublime Text" + } +}, +{ + "model": "polls.choice", + "pk": 44, + "fields": { + "question": 7, + "choice_text": "Notepad++" + } +}, +{ + "model": "polls.choice", + "pk": 45, + "fields": { + "question": 7, + "choice_text": "Atom" + } +}, +{ + "model": "polls.choice", + "pk": 46, + "fields": { + "question": 7, + "choice_text": "Neovim" + } +}, +{ + "model": "polls.choice", + "pk": 47, + "fields": { + "question": 7, + "choice_text": "Notepad" + } +}, +{ + "model": "polls.choice", + "pk": 48, + "fields": { + "question": 7, + "choice_text": "Visual Studio" + } +}, +{ + "model": "polls.choice", + "pk": 49, + "fields": { + "question": 7, + "choice_text": "Powerpoint" + } +}, +{ + "model": "polls.choice", + "pk": 50, + "fields": { + "question": 3, + "choice_text": "Maybe" + } +}, +{ + "model": "polls.choice", + "pk": 51, + "fields": { + "question": 14, + "choice_text": "Mathematics" + } +}, +{ + "model": "polls.choice", + "pk": 52, + "fields": { + "question": 14, + "choice_text": "Geography" + } +}, +{ + "model": "polls.choice", + "pk": 53, + "fields": { + "question": 14, + "choice_text": "Economics" + } +}, +{ + "model": "polls.choice", + "pk": 54, + "fields": { + "question": 14, + "choice_text": "Physics" + } +}, +{ + "model": "polls.choice", + "pk": 55, + "fields": { + "question": 14, + "choice_text": "History" + } +}, +{ + "model": "polls.choice", + "pk": 56, + "fields": { + "question": 14, + "choice_text": "Biology" + } +}, +{ + "model": "polls.choice", + "pk": 57, + "fields": { + "question": 14, + "choice_text": "Chemistry" + } +}, +{ + "model": "polls.choice", + "pk": 58, + "fields": { + "question": 14, + "choice_text": "Psychology" + } +}, +{ + "model": "polls.choice", + "pk": 59, + "fields": { + "question": 14, + "choice_text": "Philosophy" + } +}, +{ + "model": "polls.choice", + "pk": 60, + "fields": { + "question": 14, + "choice_text": "Other." + } +}, +{ + "model": "polls.choice", + "pk": 61, + "fields": { + "question": 9, + "choice_text": "Other" + } +}, +{ + "model": "polls.choice", + "pk": 62, + "fields": { + "question": 3, + "choice_text": "No Opinion." + } +}, +{ + "model": "polls.vote", + "pk": 1, + "fields": { + "choice": 1, + "user": 1, + "question": 1 + } +}, +{ + "model": "polls.vote", + "pk": 2, + "fields": { + "choice": 1, + "user": 3, + "question": 1 + } +}, +{ + "model": "polls.vote", + "pk": 3, + "fields": { + "choice": 2, + "user": 2, + "question": 1 + } +}, +{ + "model": "polls.vote", + "pk": 4, + "fields": { + "choice": 7, + "user": 2, + "question": 4 + } +}, +{ + "model": "polls.vote", + "pk": 5, + "fields": { + "choice": 6, + "user": 2, + "question": 3 + } +}, +{ + "model": "polls.vote", + "pk": 6, + "fields": { + "choice": 3, + "user": 2, + "question": 2 + } +}, +{ + "model": "polls.vote", + "pk": 7, + "fields": { + "choice": 8, + "user": 4, + "question": 4 + } +}, +{ + "model": "polls.vote", + "pk": 8, + "fields": { + "choice": 6, + "user": 4, + "question": 3 + } +}, +{ + "model": "polls.vote", + "pk": 9, + "fields": { + "choice": 3, + "user": 4, + "question": 2 + } +}, +{ + "model": "polls.vote", + "pk": 10, + "fields": { + "choice": 2, + "user": 4, + "question": 1 + } +}, +{ + "model": "polls.vote", + "pk": 11, + "fields": { + "choice": 6, + "user": 3, + "question": 3 + } +}, +{ + "model": "polls.vote", + "pk": 12, + "fields": { + "choice": 3, + "user": 3, + "question": 2 + } +}, +{ + "model": "polls.vote", + "pk": 13, + "fields": { + "choice": 6, + "user": 6, + "question": 3 + } +}, +{ + "model": "polls.vote", + "pk": 14, + "fields": { + "choice": 7, + "user": 3, + "question": 4 + } +}, +{ + "model": "polls.vote", + "pk": 15, + "fields": { + "choice": 2, + "user": 6, + "question": 1 + } +}, +{ + "model": "polls.vote", + "pk": 16, + "fields": { + "choice": 9, + "user": 1, + "question": 4 + } +}, +{ + "model": "polls.vote", + "pk": 17, + "fields": { + "choice": 6, + "user": 1, + "question": 3 + } +}, +{ + "model": "polls.vote", + "pk": 18, + "fields": { + "choice": 25, + "user": 2, + "question": 8 + } +}, +{ + "model": "polls.vote", + "pk": 19, + "fields": { + "choice": 15, + "user": 2, + "question": 7 + } +}, +{ + "model": "polls.vote", + "pk": 20, + "fields": { + "choice": 24, + "user": 4, + "question": 8 + } +}, +{ + "model": "polls.vote", + "pk": 21, + "fields": { + "choice": 25, + "user": 3, + "question": 8 + } +}, +{ + "model": "polls.vote", + "pk": 22, + "fields": { + "choice": 14, + "user": 3, + "question": 6 + } +}, +{ + "model": "polls.vote", + "pk": 23, + "fields": { + "choice": 28, + "user": 3, + "question": 9 + } +}, +{ + "model": "polls.vote", + "pk": 24, + "fields": { + "choice": 27, + "user": 6, + "question": 8 + } +}, +{ + "model": "polls.vote", + "pk": 25, + "fields": { + "choice": 15, + "user": 6, + "question": 7 + } +}, +{ + "model": "polls.vote", + "pk": 26, + "fields": { + "choice": 29, + "user": 6, + "question": 9 + } +}, +{ + "model": "polls.vote", + "pk": 27, + "fields": { + "choice": 26, + "user": 1, + "question": 8 + } +}, +{ + "model": "polls.vote", + "pk": 28, + "fields": { + "choice": 28, + "user": 1, + "question": 9 + } +}, +{ + "model": "polls.vote", + "pk": 29, + "fields": { + "choice": 12, + "user": 1, + "question": 6 + } +}, +{ + "model": "polls.sentimentvote", + "pk": 1, + "fields": { + "user": 1, + "question": 1, + "vote_types": false + } +}, +{ + "model": "polls.sentimentvote", + "pk": 2, + "fields": { + "user": 2, + "question": 2, + "vote_types": true + } +}, +{ + "model": "polls.sentimentvote", + "pk": 3, + "fields": { + "user": 2, + "question": 4, + "vote_types": true + } +}, +{ + "model": "polls.sentimentvote", + "pk": 4, + "fields": { + "user": 2, + "question": 3, + "vote_types": false + } +}, +{ + "model": "polls.sentimentvote", + "pk": 5, + "fields": { + "user": 2, + "question": 1, + "vote_types": false + } +}, +{ + "model": "polls.sentimentvote", + "pk": 6, + "fields": { + "user": 6, + "question": 1, + "vote_types": true + } +}, +{ + "model": "polls.sentimentvote", + "pk": 7, + "fields": { + "user": 6, + "question": 3, + "vote_types": true + } +}, +{ + "model": "polls.sentimentvote", + "pk": 8, + "fields": { + "user": 6, + "question": 4, + "vote_types": true + } +}, +{ + "model": "polls.sentimentvote", + "pk": 9, + "fields": { + "user": 3, + "question": 1, + "vote_types": false + } +}, +{ + "model": "polls.sentimentvote", + "pk": 10, + "fields": { + "user": 3, + "question": 3, + "vote_types": true + } +}, +{ + "model": "polls.sentimentvote", + "pk": 11, + "fields": { + "user": 3, + "question": 4, + "vote_types": false + } +}, +{ + "model": "polls.sentimentvote", + "pk": 12, + "fields": { + "user": 3, + "question": 2, + "vote_types": true + } +}, +{ + "model": "polls.sentimentvote", + "pk": 14, + "fields": { + "user": 1, + "question": 4, + "vote_types": false + } +}, +{ + "model": "polls.sentimentvote", + "pk": 15, + "fields": { + "user": 1, + "question": 3, + "vote_types": true + } +}, +{ + "model": "polls.sentimentvote", + "pk": 16, + "fields": { + "user": 1, + "question": 2, + "vote_types": false + } +}, +{ + "model": "polls.sentimentvote", + "pk": 17, + "fields": { + "user": 2, + "question": 8, + "vote_types": true + } +}, +{ + "model": "polls.sentimentvote", + "pk": 18, + "fields": { + "user": 2, + "question": 7, + "vote_types": true + } +}, +{ + "model": "polls.sentimentvote", + "pk": 19, + "fields": { + "user": 4, + "question": 8, + "vote_types": true + } +}, +{ + "model": "polls.sentimentvote", + "pk": 20, + "fields": { + "user": 3, + "question": 8, + "vote_types": true + } +}, +{ + "model": "polls.sentimentvote", + "pk": 21, + "fields": { + "user": 3, + "question": 6, + "vote_types": false + } +}, +{ + "model": "polls.sentimentvote", + "pk": 22, + "fields": { + "user": 3, + "question": 9, + "vote_types": false + } +}, +{ + "model": "polls.sentimentvote", + "pk": 23, + "fields": { + "user": 6, + "question": 8, + "vote_types": true + } +}, +{ + "model": "polls.sentimentvote", + "pk": 24, + "fields": { + "user": 6, + "question": 9, + "vote_types": false + } +}, +{ + "model": "polls.sentimentvote", + "pk": 25, + "fields": { + "user": 1, + "question": 8, + "vote_types": true + } +}, +{ + "model": "polls.sentimentvote", + "pk": 26, + "fields": { + "user": 1, + "question": 6, + "vote_types": true + } +}, +{ + "model": "polls.sentimentvote", + "pk": 27, + "fields": { + "user": 1, + "question": 9, + "vote_types": false + } +}, +{ + "model": "auth.user", + "pk": 1, + "fields": { + "password": "pbkdf2_sha256$600000$aDh9a1PXxcXAb8z3YIjAPX$NVH24kt/wMad+0fZcCii738dfojI4vL2ffXOwNRuLz4=", + "last_login": "2023-09-17T16:33:12.136Z", + "is_superuser": true, + "username": "admin", + "first_name": "", + "last_name": "", + "email": "admin@email.com", + "is_staff": true, + "is_active": true, + "date_joined": "2023-09-11T18:24:20.740Z", + "groups": [], + "user_permissions": [] + } +}, +{ + "model": "auth.user", + "pk": 2, + "fields": { + "password": "pbkdf2_sha256$600000$quZKLKT8Ec3TQgpdqlCkpX$o+VOOnRDLGf64qjHb239Yvsre74tPkC8hw1qH1un/hk=", + "last_login": "2023-09-17T16:07:12.447Z", + "is_superuser": false, + "username": "tester1", + "first_name": "", + "last_name": "", + "email": "", + "is_staff": false, + "is_active": true, + "date_joined": "2023-09-11T19:41:22.592Z", + "groups": [], + "user_permissions": [] + } +}, +{ + "model": "auth.user", + "pk": 3, + "fields": { + "password": "pbkdf2_sha256$600000$1xGp6EDCoaljdTlSdVT1Mn$UID0Woeh8hwW7LtchH+hKzqdKTDeITTxQ/0DGvfG3CY=", + "last_login": "2023-09-15T16:36:24.774Z", + "is_superuser": false, + "username": "tester3", + "first_name": "", + "last_name": "", + "email": "", + "is_staff": false, + "is_active": true, + "date_joined": "2023-09-11T19:41:41.209Z", + "groups": [], + "user_permissions": [] + } +}, +{ + "model": "auth.user", + "pk": 4, + "fields": { + "password": "pbkdf2_sha256$600000$fJJcIwAuIESYwZDBOqBv8t$YEDVCgg/xJOqAOiAdvGvvqgi1jgn1YfYHJE9yx2JWTA=", + "last_login": "2023-09-15T16:35:58.248Z", + "is_superuser": false, + "username": "tester2", + "first_name": "", + "last_name": "", + "email": "", + "is_staff": false, + "is_active": true, + "date_joined": "2023-09-11T19:43:25.226Z", + "groups": [], + "user_permissions": [] + } +}, +{ + "model": "auth.user", + "pk": 5, + "fields": { + "password": "pbkdf2_sha256$600000$aHyU2gjOR6Vfsh3DBMIvQy$PZwRu+rOLc+N15DDguvy29dks6GUiN5YN/4io8b390o=", + "last_login": "2023-09-14T14:49:50.765Z", + "is_superuser": false, + "username": "novote", + "first_name": "", + "last_name": "", + "email": "", + "is_staff": false, + "is_active": true, + "date_joined": "2023-09-11T19:52:38.130Z", + "groups": [], + "user_permissions": [] + } +}, +{ + "model": "auth.user", + "pk": 6, + "fields": { + "password": "pbkdf2_sha256$600000$5rNKsClojvcsBqzrEmAzy5$XpeAUCrzeLG42H+8o4HBVqifKd0cQuWcEhFax/dxS5M=", + "last_login": "2023-09-15T16:37:53.221Z", + "is_superuser": false, + "username": "tester4", + "first_name": "", + "last_name": "", + "email": "", + "is_staff": false, + "is_active": true, + "date_joined": "2023-09-14T11:37:58.740Z", + "groups": [], + "user_permissions": [] + } +}, +{ + "model": "auth.user", + "pk": 8, + "fields": { + "password": "pbkdf2_sha256$600000$QL1ktlWKsyyG2IASDFrJTQ$L7vKabykHi4ir3IcCf3qE9tj/TrAyyfQMekQ4xj+s7I=", + "last_login": "2023-09-15T17:23:08.479Z", + "is_superuser": false, + "username": "tester5", + "first_name": "", + "last_name": "", + "email": "", + "is_staff": false, + "is_active": true, + "date_joined": "2023-09-15T17:23:07.965Z", + "groups": [], + "user_permissions": [] + } +} +] diff --git a/data/polls-v1.json b/data/polls-v1.json deleted file mode 100644 index 1c95e50..0000000 --- a/data/polls-v1.json +++ /dev/null @@ -1,180 +0,0 @@ -[ -{ - "model": "polls.question", - "pk": 1, - "fields": { - "question_text": "Python vs C++, which one is better in your opinion?", - "short_description": "Cool kids have polls", - "long_description": "No description provide for this poll.", - "pub_date": "2023-08-28T13:38:42Z", - "end_date": "2025-09-24T22:56:52Z", - "up_vote_count": 0, - "down_vote_count": 0, - "participant_count": 0 - } -}, -{ - "model": "polls.question", - "pk": 2, - "fields": { - "question_text": "The chicken and the egg, which came first?", - "short_description": "Cool kids have polls", - "long_description": "No description provide for this poll.", - "pub_date": "2023-08-28T13:39:16Z", - "end_date": "2023-11-05T06:30:16Z", - "up_vote_count": 12, - "down_vote_count": 4, - "participant_count": 11 - } -}, -{ - "model": "polls.question", - "pk": 3, - "fields": { - "question_text": "Do you love Django?", - "short_description": "Cool kids have polls", - "long_description": "No description provide for this poll.", - "pub_date": "2023-11-07T15:40:31Z", - "end_date": "2023-09-20T13:41:33Z", - "up_vote_count": 3000, - "down_vote_count": 50, - "participant_count": 555 - } -}, -{ - "model": "polls.question", - "pk": 4, - "fields": { - "question_text": "So far so good?", - "short_description": "Cool kids have polls", - "long_description": "No description provide for this poll.", - "pub_date": "2023-09-09T06:30:50.690Z", - "end_date": "2023-09-30T12:54:30Z", - "up_vote_count": 0, - "down_vote_count": 0, - "participant_count": 234 - } -}, -{ - "model": "polls.question", - "pk": 5, - "fields": { - "question_text": "Do you love Django?", - "short_description": "Cool kids have polls", - "long_description": "No description provide for this poll.", - "pub_date": "2023-09-09T13:42:27.501Z", - "end_date": "2023-09-21T13:42:17Z", - "up_vote_count": 1, - "down_vote_count": 1, - "participant_count": 1 - } -}, -{ - "model": "polls.choice", - "pk": 4, - "fields": { - "question": 2, - "choice_text": "Chicken", - "votes": 55 - } -}, -{ - "model": "polls.choice", - "pk": 5, - "fields": { - "question": 2, - "choice_text": "Egg", - "votes": 56 - } -}, -{ - "model": "polls.choice", - "pk": 6, - "fields": { - "question": 1, - "choice_text": "Python!", - "votes": 6 - } -}, -{ - "model": "polls.choice", - "pk": 7, - "fields": { - "question": 1, - "choice_text": "C++", - "votes": 3 - } -}, -{ - "model": "polls.choice", - "pk": 8, - "fields": { - "question": 3, - "choice_text": "Yeah for sure!", - "votes": 0 - } -}, -{ - "model": "polls.choice", - "pk": 9, - "fields": { - "question": 3, - "choice_text": "nah", - "votes": 0 - } -}, -{ - "model": "polls.choice", - "pk": 13, - "fields": { - "question": 4, - "choice_text": "Yes!", - "votes": 5 - } -}, -{ - "model": "polls.choice", - "pk": 14, - "fields": { - "question": 4, - "choice_text": "No!", - "votes": 4 - } -}, -{ - "model": "polls.choice", - "pk": 15, - "fields": { - "question": 4, - "choice_text": "Okay!", - "votes": 5 - } -}, -{ - "model": "polls.choice", - "pk": 16, - "fields": { - "question": 4, - "choice_text": "Thank you!", - "votes": 2 - } -}, -{ - "model": "polls.choice", - "pk": 17, - "fields": { - "question": 5, - "choice_text": "Yeah for sure!", - "votes": 2 - } -}, -{ - "model": "polls.choice", - "pk": 18, - "fields": { - "question": 5, - "choice_text": "nah", - "votes": 2 - } -} -] diff --git a/data/polls.json b/data/polls.json index 6d5302b..d6d08fb 100644 --- a/data/polls.json +++ b/data/polls.json @@ -9,7 +9,9 @@ "short_description": "🐍 vs πŸ‡¨ ++", "long_description": "Let them fight.", "trend_score": 60.0, - "tags": [] + "tags": [ + 7 + ] } }, { @@ -22,7 +24,9 @@ "short_description": "Classic question.", "long_description": "Most biologists state unequivocally that the egg came first. At their most basic level, eggs are just female sex cells. Hard external eggs that can be laid on land (also known as amniotic eggs) were a game changer for vertebrates. Anyway, let select you choice.", "trend_score": 140.0, - "tags": [] + "tags": [ + 4 + ] } }, { @@ -35,7 +39,9 @@ "short_description": "If you know, you know.", "long_description": "The sentence where you will hear once every week.", "trend_score": 120.0, - "tags": [] + "tags": [ + 6 + ] } }, { @@ -48,7 +54,9 @@ "short_description": "Djago, I love it!", "long_description": "Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. Built by experienced developers, it takes care of much of the hassle of web development, so you can focus on writing your app without needing to reinvent the wheel. It’s free and open source.", "trend_score": 120.0, - "tags": [] + "tags": [ + 7 + ] } }, { @@ -61,7 +69,9 @@ "short_description": "Swifty vs Ye Club", "long_description": "It's no secret that Taylor Swift and Kanye West's relationship can be described as volatile at best. Let choose!", "trend_score": 100.0, - "tags": [] + "tags": [ + 8 + ] } }, { @@ -74,7 +84,9 @@ "short_description": "Please do my pollπŸ₯Ί", "long_description": "My favorite code editor is VScode. What about you?", "trend_score": 100.0, - "tags": [] + "tags": [ + 7 + ] } }, { @@ -82,12 +94,15 @@ "pk": 8, "fields": { "question_text": "Which one is the best RIZZ line?", - "pub_date": "2023-09-14T15:52:03Z", - "end_date": "2023-11-14T17:00:00Z", + "pub_date": "2023-09-17T16:39:52Z", + "end_date": "2023-12-12T17:00:00Z", "short_description": "RIZZ (noun) How good you are with flirting", "long_description": "Rizz actually comes from the word charisma. It's a NYC Slang created by a twitch streamer named Kai cenat. This means that you have game, a good flirt line.", "trend_score": 100.0, - "tags": [] + "tags": [ + 5, + 6 + ] } }, { @@ -100,7 +115,24 @@ "short_description": "Pizza without topping is not pizza!", "long_description": "I mean, Yeah here are the choices ;)", "trend_score": 100.0, - "tags": [] + "tags": [ + 4 + ] + } +}, +{ + "model": "polls.question", + "pk": 14, + "fields": { + "question_text": "What is your favorite subjects?", + "pub_date": "2023-09-17T16:37:49Z", + "end_date": "2023-11-29T16:37:53Z", + "short_description": "Which subjects do you love?", + "long_description": "Here are the list of subjects, which one is the best for you!", + "trend_score": 100.0, + "tags": [ + 9 + ] } }, { @@ -196,7 +228,7 @@ "pk": 12, "fields": { "question": 6, - "choice_text": "Neither" + "choice_text": "Nobody is better than others." } }, { @@ -228,7 +260,7 @@ "pk": 16, "fields": { "question": 7, - "choice_text": "IntelliJ IDEA" + "choice_text": "JetBrains IDE" } }, { @@ -368,462 +400,245 @@ } }, { - "model": "polls.vote", - "pk": 1, + "model": "polls.choice", + "pk": 38, "fields": { - "choice": 1, - "user": 1, - "question": 1 + "question": 9, + "choice_text": "Pepperoni" } }, { - "model": "polls.vote", - "pk": 2, + "model": "polls.choice", + "pk": 39, "fields": { - "choice": 1, - "user": 3, - "question": 1 + "question": 9, + "choice_text": "Chicken breast" } }, { - "model": "polls.vote", - "pk": 3, + "model": "polls.choice", + "pk": 40, "fields": { - "choice": 2, - "user": 2, - "question": 1 + "question": 9, + "choice_text": "Mushrooms" } }, { - "model": "polls.vote", - "pk": 4, + "model": "polls.choice", + "pk": 41, "fields": { - "choice": 7, - "user": 2, - "question": 4 + "question": 9, + "choice_text": "Tomato" } }, { - "model": "polls.vote", - "pk": 5, + "model": "polls.choice", + "pk": 42, "fields": { - "choice": 6, - "user": 2, - "question": 3 + "question": 9, + "choice_text": "Onions" } }, { - "model": "polls.vote", - "pk": 6, + "model": "polls.choice", + "pk": 43, "fields": { - "choice": 3, - "user": 2, - "question": 2 - } -}, -{ - "model": "polls.vote", - "pk": 7, - "fields": { - "choice": 8, - "user": 4, - "question": 4 - } -}, -{ - "model": "polls.vote", - "pk": 8, - "fields": { - "choice": 6, - "user": 4, - "question": 3 - } -}, -{ - "model": "polls.vote", - "pk": 9, - "fields": { - "choice": 3, - "user": 4, - "question": 2 - } -}, -{ - "model": "polls.vote", - "pk": 10, - "fields": { - "choice": 2, - "user": 4, - "question": 1 - } -}, -{ - "model": "polls.vote", - "pk": 11, - "fields": { - "choice": 6, - "user": 3, - "question": 3 - } -}, -{ - "model": "polls.vote", - "pk": 12, - "fields": { - "choice": 3, - "user": 3, - "question": 2 - } -}, -{ - "model": "polls.vote", - "pk": 13, - "fields": { - "choice": 6, - "user": 6, - "question": 3 - } -}, -{ - "model": "polls.vote", - "pk": 14, - "fields": { - "choice": 7, - "user": 3, - "question": 4 - } -}, -{ - "model": "polls.vote", - "pk": 15, - "fields": { - "choice": 2, - "user": 6, - "question": 1 - } -}, -{ - "model": "polls.vote", - "pk": 16, - "fields": { - "choice": 9, - "user": 1, - "question": 4 - } -}, -{ - "model": "polls.vote", - "pk": 17, - "fields": { - "choice": 6, - "user": 1, - "question": 3 - } -}, -{ - "model": "polls.vote", - "pk": 18, - "fields": { - "choice": 25, - "user": 2, - "question": 8 - } -}, -{ - "model": "polls.vote", - "pk": 19, - "fields": { - "choice": 15, - "user": 2, - "question": 7 - } -}, -{ - "model": "polls.vote", - "pk": 20, - "fields": { - "choice": 24, - "user": 4, - "question": 8 - } -}, -{ - "model": "polls.vote", - "pk": 21, - "fields": { - "choice": 25, - "user": 3, - "question": 8 - } -}, -{ - "model": "polls.vote", - "pk": 22, - "fields": { - "choice": 14, - "user": 3, - "question": 6 - } -}, -{ - "model": "polls.vote", - "pk": 23, - "fields": { - "choice": 28, - "user": 3, - "question": 9 - } -}, -{ - "model": "polls.vote", - "pk": 24, - "fields": { - "choice": 27, - "user": 6, - "question": 8 - } -}, -{ - "model": "polls.vote", - "pk": 25, - "fields": { - "choice": 15, - "user": 6, - "question": 7 - } -}, -{ - "model": "polls.vote", - "pk": 26, - "fields": { - "choice": 29, - "user": 6, - "question": 9 - } -}, -{ - "model": "polls.vote", - "pk": 27, - "fields": { - "choice": 26, - "user": 1, - "question": 8 - } -}, -{ - "model": "polls.sentimentvote", - "pk": 1, - "fields": { - "user": 1, - "question": 1, - "vote_types": false - } -}, -{ - "model": "polls.sentimentvote", - "pk": 2, - "fields": { - "user": 2, - "question": 2, - "vote_types": true - } -}, -{ - "model": "polls.sentimentvote", - "pk": 3, - "fields": { - "user": 2, - "question": 4, - "vote_types": true - } -}, -{ - "model": "polls.sentimentvote", - "pk": 4, - "fields": { - "user": 2, - "question": 3, - "vote_types": false - } -}, -{ - "model": "polls.sentimentvote", - "pk": 5, - "fields": { - "user": 2, - "question": 1, - "vote_types": false - } -}, -{ - "model": "polls.sentimentvote", - "pk": 6, - "fields": { - "user": 6, - "question": 1, - "vote_types": true - } -}, -{ - "model": "polls.sentimentvote", - "pk": 7, - "fields": { - "user": 6, - "question": 3, - "vote_types": true - } -}, -{ - "model": "polls.sentimentvote", - "pk": 8, - "fields": { - "user": 6, - "question": 4, - "vote_types": true - } -}, -{ - "model": "polls.sentimentvote", - "pk": 9, - "fields": { - "user": 3, - "question": 1, - "vote_types": false - } -}, -{ - "model": "polls.sentimentvote", - "pk": 10, - "fields": { - "user": 3, - "question": 3, - "vote_types": true - } -}, -{ - "model": "polls.sentimentvote", - "pk": 11, - "fields": { - "user": 3, - "question": 4, - "vote_types": false - } -}, -{ - "model": "polls.sentimentvote", - "pk": 12, - "fields": { - "user": 3, - "question": 2, - "vote_types": true - } -}, -{ - "model": "polls.sentimentvote", - "pk": 14, - "fields": { - "user": 1, - "question": 4, - "vote_types": false - } -}, -{ - "model": "polls.sentimentvote", - "pk": 15, - "fields": { - "user": 1, - "question": 3, - "vote_types": true - } -}, -{ - "model": "polls.sentimentvote", - "pk": 16, - "fields": { - "user": 1, - "question": 2, - "vote_types": false - } -}, -{ - "model": "polls.sentimentvote", - "pk": 17, - "fields": { - "user": 2, - "question": 8, - "vote_types": true - } -}, -{ - "model": "polls.sentimentvote", - "pk": 18, - "fields": { - "user": 2, "question": 7, - "vote_types": true + "choice_text": "Sublime Text" } }, { - "model": "polls.sentimentvote", - "pk": 19, + "model": "polls.choice", + "pk": 44, "fields": { - "user": 4, - "question": 8, - "vote_types": true + "question": 7, + "choice_text": "Notepad++" } }, { - "model": "polls.sentimentvote", - "pk": 20, + "model": "polls.choice", + "pk": 45, "fields": { - "user": 3, - "question": 8, - "vote_types": true + "question": 7, + "choice_text": "Atom" } }, { - "model": "polls.sentimentvote", - "pk": 21, + "model": "polls.choice", + "pk": 46, "fields": { - "user": 3, - "question": 6, - "vote_types": false + "question": 7, + "choice_text": "Neovim" } }, { - "model": "polls.sentimentvote", - "pk": 22, + "model": "polls.choice", + "pk": 47, + "fields": { + "question": 7, + "choice_text": "Notepad" + } +}, +{ + "model": "polls.choice", + "pk": 48, + "fields": { + "question": 7, + "choice_text": "Visual Studio" + } +}, +{ + "model": "polls.choice", + "pk": 49, + "fields": { + "question": 7, + "choice_text": "Powerpoint" + } +}, +{ + "model": "polls.choice", + "pk": 50, + "fields": { + "question": 3, + "choice_text": "Maybe" + } +}, +{ + "model": "polls.choice", + "pk": 51, + "fields": { + "question": 14, + "choice_text": "Mathematics" + } +}, +{ + "model": "polls.choice", + "pk": 52, + "fields": { + "question": 14, + "choice_text": "Geography" + } +}, +{ + "model": "polls.choice", + "pk": 53, + "fields": { + "question": 14, + "choice_text": "Economics" + } +}, +{ + "model": "polls.choice", + "pk": 54, + "fields": { + "question": 14, + "choice_text": "Physics" + } +}, +{ + "model": "polls.choice", + "pk": 55, + "fields": { + "question": 14, + "choice_text": "History" + } +}, +{ + "model": "polls.choice", + "pk": 56, + "fields": { + "question": 14, + "choice_text": "Biology" + } +}, +{ + "model": "polls.choice", + "pk": 57, + "fields": { + "question": 14, + "choice_text": "Chemistry" + } +}, +{ + "model": "polls.choice", + "pk": 58, + "fields": { + "question": 14, + "choice_text": "Psychology" + } +}, +{ + "model": "polls.choice", + "pk": 59, + "fields": { + "question": 14, + "choice_text": "Philosophy" + } +}, +{ + "model": "polls.choice", + "pk": 60, + "fields": { + "question": 14, + "choice_text": "Other." + } +}, +{ + "model": "polls.choice", + "pk": 61, "fields": { - "user": 3, "question": 9, - "vote_types": false + "choice_text": "Other" } }, { - "model": "polls.sentimentvote", - "pk": 23, + "model": "polls.choice", + "pk": 62, "fields": { - "user": 6, - "question": 8, - "vote_types": true + "question": 3, + "choice_text": "No Opinion." } }, { - "model": "polls.sentimentvote", - "pk": 24, + "model": "polls.tag", + "pk": 4, "fields": { - "user": 6, - "question": 9, - "vote_types": false + "tag_text": "Food" } }, { - "model": "polls.sentimentvote", - "pk": 25, + "model": "polls.tag", + "pk": 5, "fields": { - "user": 1, - "question": 8, - "vote_types": true + "tag_text": "Flirt" + } +}, +{ + "model": "polls.tag", + "pk": 6, + "fields": { + "tag_text": "Meme" + } +}, +{ + "model": "polls.tag", + "pk": 7, + "fields": { + "tag_text": "Programming" + } +}, +{ + "model": "polls.tag", + "pk": 8, + "fields": { + "tag_text": "Singer" + } +}, +{ + "model": "polls.tag", + "pk": 9, + "fields": { + "tag_text": "Education" } } ] diff --git a/data/users.json b/data/users.json index df0f9e3..02d898b 100644 --- a/data/users.json +++ b/data/users.json @@ -4,7 +4,7 @@ "pk": 1, "fields": { "password": "pbkdf2_sha256$600000$aDh9a1PXxcXAb8z3YIjAPX$NVH24kt/wMad+0fZcCii738dfojI4vL2ffXOwNRuLz4=", - "last_login": "2023-09-15T17:09:43.310Z", + "last_login": "2023-09-17T16:33:12.136Z", "is_superuser": true, "username": "admin", "first_name": "", @@ -22,7 +22,7 @@ "pk": 2, "fields": { "password": "pbkdf2_sha256$600000$quZKLKT8Ec3TQgpdqlCkpX$o+VOOnRDLGf64qjHb239Yvsre74tPkC8hw1qH1un/hk=", - "last_login": "2023-09-15T17:07:42.782Z", + "last_login": "2023-09-17T16:07:12.447Z", "is_superuser": false, "username": "tester1", "first_name": "", @@ -109,18 +109,18 @@ }, { "model": "auth.user", - "pk": 7, + "pk": 8, "fields": { - "password": "1234", - "last_login": null, + "password": "pbkdf2_sha256$600000$QL1ktlWKsyyG2IASDFrJTQ$L7vKabykHi4ir3IcCf3qE9tj/TrAyyfQMekQ4xj+s7I=", + "last_login": "2023-09-15T17:23:08.479Z", "is_superuser": false, - "username": "test", + "username": "tester5", "first_name": "", "last_name": "", "email": "", "is_staff": false, "is_active": true, - "date_joined": "2023-09-15T11:53:22.035Z", + "date_joined": "2023-09-15T17:23:07.965Z", "groups": [], "user_permissions": [] } diff --git a/data/vote.json b/data/vote.json new file mode 100644 index 0000000..db2af7f --- /dev/null +++ b/data/vote.json @@ -0,0 +1,263 @@ +[ +{ + "model": "polls.vote", + "pk": 1, + "fields": { + "choice": 1, + "user": 1, + "question": 1 + } +}, +{ + "model": "polls.vote", + "pk": 2, + "fields": { + "choice": 1, + "user": 3, + "question": 1 + } +}, +{ + "model": "polls.vote", + "pk": 3, + "fields": { + "choice": 2, + "user": 2, + "question": 1 + } +}, +{ + "model": "polls.vote", + "pk": 4, + "fields": { + "choice": 7, + "user": 2, + "question": 4 + } +}, +{ + "model": "polls.vote", + "pk": 5, + "fields": { + "choice": 6, + "user": 2, + "question": 3 + } +}, +{ + "model": "polls.vote", + "pk": 6, + "fields": { + "choice": 3, + "user": 2, + "question": 2 + } +}, +{ + "model": "polls.vote", + "pk": 7, + "fields": { + "choice": 8, + "user": 4, + "question": 4 + } +}, +{ + "model": "polls.vote", + "pk": 8, + "fields": { + "choice": 6, + "user": 4, + "question": 3 + } +}, +{ + "model": "polls.vote", + "pk": 9, + "fields": { + "choice": 3, + "user": 4, + "question": 2 + } +}, +{ + "model": "polls.vote", + "pk": 10, + "fields": { + "choice": 2, + "user": 4, + "question": 1 + } +}, +{ + "model": "polls.vote", + "pk": 11, + "fields": { + "choice": 6, + "user": 3, + "question": 3 + } +}, +{ + "model": "polls.vote", + "pk": 12, + "fields": { + "choice": 3, + "user": 3, + "question": 2 + } +}, +{ + "model": "polls.vote", + "pk": 13, + "fields": { + "choice": 6, + "user": 6, + "question": 3 + } +}, +{ + "model": "polls.vote", + "pk": 14, + "fields": { + "choice": 7, + "user": 3, + "question": 4 + } +}, +{ + "model": "polls.vote", + "pk": 15, + "fields": { + "choice": 2, + "user": 6, + "question": 1 + } +}, +{ + "model": "polls.vote", + "pk": 16, + "fields": { + "choice": 9, + "user": 1, + "question": 4 + } +}, +{ + "model": "polls.vote", + "pk": 17, + "fields": { + "choice": 6, + "user": 1, + "question": 3 + } +}, +{ + "model": "polls.vote", + "pk": 18, + "fields": { + "choice": 25, + "user": 2, + "question": 8 + } +}, +{ + "model": "polls.vote", + "pk": 19, + "fields": { + "choice": 15, + "user": 2, + "question": 7 + } +}, +{ + "model": "polls.vote", + "pk": 20, + "fields": { + "choice": 24, + "user": 4, + "question": 8 + } +}, +{ + "model": "polls.vote", + "pk": 21, + "fields": { + "choice": 25, + "user": 3, + "question": 8 + } +}, +{ + "model": "polls.vote", + "pk": 22, + "fields": { + "choice": 14, + "user": 3, + "question": 6 + } +}, +{ + "model": "polls.vote", + "pk": 23, + "fields": { + "choice": 28, + "user": 3, + "question": 9 + } +}, +{ + "model": "polls.vote", + "pk": 24, + "fields": { + "choice": 27, + "user": 6, + "question": 8 + } +}, +{ + "model": "polls.vote", + "pk": 25, + "fields": { + "choice": 15, + "user": 6, + "question": 7 + } +}, +{ + "model": "polls.vote", + "pk": 26, + "fields": { + "choice": 29, + "user": 6, + "question": 9 + } +}, +{ + "model": "polls.vote", + "pk": 27, + "fields": { + "choice": 26, + "user": 1, + "question": 8 + } +}, +{ + "model": "polls.vote", + "pk": 28, + "fields": { + "choice": 28, + "user": 1, + "question": 9 + } +}, +{ + "model": "polls.vote", + "pk": 29, + "fields": { + "choice": 12, + "user": 1, + "question": 6 + } +} +] diff --git a/polls/admin.py b/polls/admin.py index 4eb18c9..f515a0f 100644 --- a/polls/admin.py +++ b/polls/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from .models import Choice, Question +from .models import Choice, Question, Tag class ChoiceInline(admin.TabularInline): @@ -15,12 +15,15 @@ class QuestionAdmin(admin.ModelAdmin): ("End date", {"fields": ["end_date"], "classes": ["collapse"]}), ("Short Description", {"fields": ["short_description"], "classes": ["collapse"]}), ("Long Description", {"fields": ["long_description"], "classes": ["collapse"]}), + ("Add Tag", {"fields": ["tags"], "classes": ["collapse"]}) ] - list_display = ["question_text", "pub_date", "end_date", "was_published_recently", "can_vote", "trending_score"] + list_display = ["question_text", "pub_date", "end_date", "was_published_recently", "can_vote", + "trending_score", "get_tags"] inlines = [ChoiceInline] list_filter = ["pub_date", "end_date"] search_fields = ["question_text"] +# https://stackoverflow.com/questions/10904848/adding-inline-many-to-many-objects-in-django-admin admin.site.register(Question, QuestionAdmin) - \ No newline at end of file +admin.site.register(Tag) # Add Field to modify tags objects in Question diff --git a/polls/apps.py b/polls/apps.py index ab3fd84..36439c3 100644 --- a/polls/apps.py +++ b/polls/apps.py @@ -4,6 +4,7 @@ from django.apps import AppConfig class PollsConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'polls' - + def ready(self) -> None: - import polls.signals \ No newline at end of file + import polls.signals + \ No newline at end of file diff --git a/polls/forms.py b/polls/forms.py index ffdf2f8..d1fd40b 100644 --- a/polls/forms.py +++ b/polls/forms.py @@ -2,22 +2,25 @@ import logging from typing import Any from django import forms +from django.apps import apps from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.models import User +from .models import Question + class SignUpForm(UserCreationForm): - tailwind_class = "w-full border-2 border-gray-300 bg-gray-100 rounded-lg focus:ring focus:border-blue-300 focus:shadow-none" + tailwind_class = """w-full border-2 border-gray-300 bg-gray-100 rounded-lg + focus:ring focus:border-blue-300 focus:shadow-none""" logger = logging.getLogger('signup_form') - username = forms.CharField(widget=forms.TextInput(attrs={'class': tailwind_class}), - error_messages={ - 'unique': 'This username is already in use.', - 'invalid': 'Invalid username format.', - 'max_length': 'Username should not exceed 150 characters.', + username = forms.CharField(widget=forms.TextInput(attrs={'class': tailwind_class}), error_messages={ + 'unique': 'This username is already in use.', + 'invalid': 'Invalid username format.', + 'max_length': 'Username should not exceed 150 characters.', } ) password1 = forms.CharField(widget=forms.PasswordInput(attrs={'class': tailwind_class}), - error_messages={'min_length': 'Password must contain at least 8 characters.',} + error_messages={'min_length': 'Password must contain at least 8 characters.', } ) password2 = forms.CharField(widget=forms.PasswordInput(attrs={'class': tailwind_class}),) @@ -37,4 +40,50 @@ class SignUpForm(UserCreationForm): error_messages = { 'password_mismatch': "The two password fields didn't match.", - } \ No newline at end of file + } + + +class PollSearchForm(forms.Form): + q = forms.CharField() + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + +class PollCreateForm(forms.ModelForm): + box_style = """w-full py-2 px-2 border-2 border-gray-300 bg-gray-100 rounded-lg + focus:ring focus:border-blue-300 focus:shadow-none""" + large_box_style = """w-full border-2 border-gray-300 bg-gray-100 rounded-lg + focus:ring focus:border-blue-300 focus:shadow-none""" + + question_text = forms.CharField(min_length=10, max_length=100, required=True, + widget=forms.TextInput(attrs={'class': box_style, + 'placeholder': "What is your question?"})) + pub_date = forms.DateTimeField(widget=forms.DateInput(attrs={'type': 'date'})) + end_date = forms.DateTimeField(widget=forms.DateInput(attrs={'type': 'date'})) + short_description = forms.CharField(max_length=200, + widget=forms.TextInput( + attrs={'class': box_style, + 'placeholder': "Short description (Maximum 200 characters)"})) + long_description = forms.CharField(max_length=2000, + widget=forms.Textarea( + attrs={'class': large_box_style, + 'placeholder': "Long description (Maximum 2000 characters)"})) + user_choice = forms.CharField( + widget=forms.TextInput(attrs={'placeholder': 'Enter a choice'}), + required=True + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + Tag = apps.get_model('polls', 'Tag') + + tags = forms.MultipleChoiceField( + choices=[(tag.id, tag.tag_text) for tag in Tag.objects.all()], + widget=forms.CheckboxSelectMultiple, + ) + + class Meta: + model = Question + fields = ['question_text', 'pub_date', 'end_date', 'short_description', 'long_description', 'tags'] diff --git a/polls/models.py b/polls/models.py index 3fd50d5..670fbb2 100644 --- a/polls/models.py +++ b/polls/models.py @@ -12,7 +12,6 @@ Attributes: from django.db import models, IntegrityError from django.utils import timezone from django.contrib import admin -from django.db.models import Sum from django.contrib.auth.models import User @@ -23,7 +22,7 @@ class Tag(models.Model): tag_text = models.CharField(max_length=50) def __str__(self): - return self.name + return self.tag_text class Question(models.Model): @@ -128,6 +127,7 @@ class Question(models.Model): @property def time_left(self): + """Return time till ending of the poll""" return self.calculate_time_left() def calculate_vote_percentage(self): @@ -143,10 +143,12 @@ class Question(models.Model): @property def up_vote_percentage(self): + """Retrieve up vote percentage from calculate_vote_percentage""" return self.calculate_vote_percentage()[0] @property def down_vote_percentage(self): + """Retrieve down vote percentage from calculate_vote_percentage""" return self.calculate_vote_percentage()[1] @property @@ -166,7 +168,7 @@ class Question(models.Model): self.save() except IntegrityError: vote = self.sentimentvote_set.filter(user=user) - if vote[0].vote_types == False: + if vote[0].vote_types is False: vote.update(vote_types=True) self.save() else: @@ -182,7 +184,7 @@ class Question(models.Model): self.save() except IntegrityError: vote = self.sentimentvote_set.filter(user=user) - if vote[0].vote_types == True: + if vote[0].vote_types is True: vote.update(vote_types=False) self.save() else: @@ -191,10 +193,12 @@ class Question(models.Model): @property def up_vote_count(self): + """Count up vote of Question""" return self.sentimentvote_set.filter(question=self, vote_types=True).count() @property def down_vote_count(self): + """Count down vote of Question""" return self.sentimentvote_set.filter(question=self, vote_types=False).count() def trending_score(self, up=None, down=None): @@ -202,8 +206,8 @@ class Question(models.Model): published_date_duration = timezone.now() - self.pub_date score = 0 - if (published_date_duration.seconds < 259200): # Second unit - score += 100 + if (published_date_duration.seconds < 259200): # Second unit + score += 100 elif (published_date_duration.seconds < 604800): score += 75 elif (published_date_duration.seconds < 2592000): @@ -211,17 +215,20 @@ class Question(models.Model): else: score += 25 - if (up == None) and (down == None): + if (up is None) and (down is None): score += ((self.up_vote_count/5) - (self.down_vote_count/5)) * 100 else: score += ((up/5) - (down/5)) * 100 return score + def get_tags(self, *args, **kwargs): + return "-".join([tag.tag_text for tag in self.tags.all()]) def save(self, *args, **kwargs): """Modify save method of Question object""" - # to-be-added instance # * https://github.com/django/django/blob/866122690dbe233c054d06f6afbc2f3cc6aea2f2/django/db/models/base.py#L447 + # to-be-added instance + # * https://github.com/django/django/blob/866122690dbe233c054d06f6afbc2f3cc6aea2f2/django/db/models/base.py#L447 if self._state.adding: try: self.trend_score = self.trending_score() @@ -263,7 +270,7 @@ class Vote(models.Model): def __str__(self): return f"{self.user} voted for {self.choice} in {self.question}" - + # ! Most of the code from https://stackoverflow.com/a/70869267 class SentimentVote(models.Model): @@ -288,4 +295,4 @@ class SentimentVote(models.Model): unique_together (list of str): Ensures that a user can only cast one sentiment vote (upvote or downvote) for a specific question. """ - unique_together = ['user', 'question'] \ No newline at end of file + unique_together = ['user', 'question'] diff --git a/polls/signals.py b/polls/signals.py index 4f63242..8d5ed97 100644 --- a/polls/signals.py +++ b/polls/signals.py @@ -4,6 +4,7 @@ from django.dispatch import receiver log = logging.getLogger("django") + def get_client_ip(request): x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') if x_forwarded_for: @@ -12,9 +13,10 @@ def get_client_ip(request): ip = request.META.get('REMOTE_ADDR') return ip -#! https://stackoverflow.com/questions/37618473/how-can-i-log-both-successful-and-failed-login-and-logout-attempts-in-django + +# !https://stackoverflow.com/questions/37618473/how-can-i-log-both-successful-and-failed-login-and-logout-attempts-in-django @receiver(user_logged_in) -def user_logged_in_callback(sender, request, user, **kwargs): +def user_logged_in_callback(sender, request, user, **kwargs): ip = get_client_ip(request) log.info('Login User: {user} via ip: {ip}'.format( @@ -22,8 +24,9 @@ def user_logged_in_callback(sender, request, user, **kwargs): ip=ip )) + @receiver(user_logged_out) -def user_logged_out_callback(sender, request, user, **kwargs): +def user_logged_out_callback(sender, request, user, **kwargs): ip = get_client_ip(request) log.info('Logout User: {user} via ip: {ip}'.format( @@ -31,8 +34,9 @@ def user_logged_out_callback(sender, request, user, **kwargs): ip=ip )) + @receiver(user_login_failed) def user_login_failed_callback(sender, credentials, **kwargs): log.warning('Login Failed for: {credentials}'.format( credentials=credentials, - )) \ No newline at end of file + )) diff --git a/polls/templates/polls/creation.html b/polls/templates/polls/creation.html new file mode 100644 index 0000000..660e86b --- /dev/null +++ b/polls/templates/polls/creation.html @@ -0,0 +1,145 @@ +{% extends "polls/base.html" %} + +{% block content %} +
+ + +
+
+
+ + < Back + +
+ {% csrf_token %} + +
+ + {{ form.question_text }} +
+ +
+ + {{ form.pub_date }} +
+ +
+ + {{ form.end_date }} +
+ +
+ + {{ form.short_description }} +
+ +
+ + {{ form.long_description }} +
+ +
+ + {{ form.tags }} +
+ + +
+ + {{ form.user_choice }} +
+ {% comment %}
+ +
+ + +
+
+ +
+
{% endcomment %} + +
+ + Create Poll + + + +
+
+
+ + + + + +{% comment %} {% endcomment %} + +{% endblock content %} diff --git a/polls/templates/polls/index.html b/polls/templates/polls/index.html index 0dd54a0..35a6380 100644 --- a/polls/templates/polls/index.html +++ b/polls/templates/polls/index.html @@ -12,14 +12,11 @@
- {% comment %} - - {% endcomment %}
-
+
πŸ”Ž
@@ -34,9 +31,9 @@
{% if user.is_authenticated %} - + Sign out @@ -90,6 +87,7 @@

{{ question.question_text }}


{{ question.short_description }}

+
πŸ‘ {{ question.up_vote_percentage }}% Upvoted @@ -97,12 +95,20 @@ πŸ‘Ž {{ question.down_vote_percentage }}% Downvoted
- +
πŸ•’ {{ question.time_left }} {{ question.participants }} Participants πŸ‘€
-
+ + +
+ {% if q %} + {% with results.count as total_result %} +

Found {{ total_result }} Polls!

+ {% endwith %} + {% endif %} +
+
+ {% for question in results %} +
+ +
+

{{ question.question_text }}

+
+

{{ question.short_description }}

+
+ πŸ‘ + {{ question.up_vote_percentage }}% Upvoted + + πŸ‘Ž + {{ question.down_vote_percentage }}% Downvoted +
+ +
+ πŸ•’ {{ question.time_left }} + {{ question.participants }} Participants πŸ‘€ +
+
+ + +
+
+ {% if forloop.counter|divisibleby:2 %} +
+
+ {% else %} +
+
+ {% endif %} +
+ {% endfor %} +
+
+ +
+ +{% endblock content %} \ No newline at end of file diff --git a/polls/tests/base.py b/polls/tests/base.py index 1e2db85..d1e06d6 100644 --- a/polls/tests/base.py +++ b/polls/tests/base.py @@ -1,7 +1,6 @@ from django.utils import timezone -from django.contrib.auth.models import User -from ..models import Question, Vote, Choice +from ..models import Question def create_question(question_text, day=0): @@ -11,4 +10,4 @@ def create_question(question_text, day=0): in the past, positive for questions that have yet to be published). """ time = timezone.now() + timezone.timedelta(days=day) - return Question.objects.create(question_text=question_text, pub_date=time) \ No newline at end of file + return Question.objects.create(question_text=question_text, pub_date=time) diff --git a/polls/tests/test_detail_views.py b/polls/tests/test_detail_views.py index db2f3bc..07895ee 100644 --- a/polls/tests/test_detail_views.py +++ b/polls/tests/test_detail_views.py @@ -1,5 +1,4 @@ from django.test import TestCase, Client -from django.utils import timezone from django.urls import reverse from django.contrib.auth.models import User diff --git a/polls/tests/test_question_model.py b/polls/tests/test_question_model.py index f0cdd07..750dbab 100644 --- a/polls/tests/test_question_model.py +++ b/polls/tests/test_question_model.py @@ -102,4 +102,4 @@ class QuestionModelTests(TestCase): pub_date = timezone.now() - datetime.timedelta(hours=1) end_date = timezone.now() + datetime.timedelta(hours=2) question = Question(pub_date=pub_date, end_date=end_date) - self.assertIs(question.can_vote(), True) \ No newline at end of file + self.assertIs(question.can_vote(), True) diff --git a/polls/tests/test_search_poll.py b/polls/tests/test_search_poll.py new file mode 100644 index 0000000..a8709a8 --- /dev/null +++ b/polls/tests/test_search_poll.py @@ -0,0 +1,23 @@ +from django.test import TestCase +from django.urls import reverse + +from ..models import Question + + +class SearchPollTest(TestCase): + """Test if user search with normal string. It must return same queryset as filter question objects""" + def test_search_normal_poll(self): + data_1 = {'q': 'what'} + data_2 = {'q': 'prefer'} + q_1 = 'what' + q_2 = 'prefer' + response_1 = self.client.get(reverse("polls:search_poll"), data_1) + response_2 = self.client.get(reverse("polls:search_poll"), data_2) + self.assertQuerysetEqual(response_1.context['results'], Question.objects.filter(question_text__icontains=q_1)) + self.assertQuerysetEqual(response_2.context['results'], Question.objects.filter(question_text__icontains=q_2)) + + def test_search_with_empty(self): + """Test if user search with empty string. It must return all question""" + data = {'q': ''} + response = self.client.get(reverse("polls:search_poll"), data) + self.assertQuerysetEqual(response.context['results'], Question.objects.all()) diff --git a/polls/tests/test_sentiment_model.py b/polls/tests/test_sentiment_model.py index c1ede3b..97bae5f 100644 --- a/polls/tests/test_sentiment_model.py +++ b/polls/tests/test_sentiment_model.py @@ -2,7 +2,7 @@ from django.test import TransactionTestCase, Client from django.contrib.auth.models import User from .base import create_question -from ..views import up_down_vote + # ! https://stackoverflow.com/questions/24588520/testing-several-integrityerrors-in-the-same-django-unittest-test-case # * https://stackoverflow.com/questions/44450533/difference-between-testcase-and-transactiontestcase-classes-in-django-test @@ -32,11 +32,11 @@ class UpDownVoteViewTest(TransactionTestCase): self.assertEqual(count_up, 0) self.assertEqual(count_down, 1) - def test_can_change_up_to_down(self): + def test_can_change_down_to_up(self): self.client.login(username="test_user", password="12345abc") self.q1.downvote(self.user) self.q1.upvote(self.user) count_up = self.q1.sentimentvote_set.filter(vote_types=True).count() count_down = self.q1.sentimentvote_set.filter(vote_types=False).count() self.assertEqual(count_up, 1) - self.assertEqual(count_down, 0) \ No newline at end of file + self.assertEqual(count_down, 0) diff --git a/polls/tests/test_signup.py b/polls/tests/test_signup.py index 50278ee..c9bd074 100644 --- a/polls/tests/test_signup.py +++ b/polls/tests/test_signup.py @@ -42,4 +42,4 @@ class SignUpTestCase(TestCase): 'password2': 'testpassword123', } response = self.client.post(signup_url, data) - self.assertRedirects(response, reverse("polls:index")) \ No newline at end of file + self.assertRedirects(response, reverse("polls:index")) diff --git a/polls/tests/test_vote_views.py b/polls/tests/test_vote_views.py index 393650e..af8b3c3 100644 --- a/polls/tests/test_vote_views.py +++ b/polls/tests/test_vote_views.py @@ -5,6 +5,7 @@ from django.contrib.auth.models import User from .base import create_question from ..models import Vote, Choice + class VoteViewTest(TestCase): @classmethod def setUpTestData(cls): @@ -20,9 +21,9 @@ class VoteViewTest(TestCase): """ self.client.login(username=self.user.username, password="aaa123321aaa") - response = self.client.post(reverse("polls:vote", args=(self.question.id,)), - {'choice' : self.choice1.id}) - + response = self.client.post(reverse("polls:vote", args=(self.question.id,)), + {'choice': self.choice1.id}) + self.assertRedirects(response, reverse("polls:results", args=(self.question.id,))) self.assertTrue(Vote.objects.filter(user=self.user, question=self.question).exists()) @@ -32,18 +33,18 @@ class VoteViewTest(TestCase): """ self.client.login(username=self.user.username, password="aaa123321aaa") - response = self.client.post(reverse("polls:vote", args=(self.question.id,)), - {'choice' : 1000}) - + response = self.client.post(reverse("polls:vote", args=(self.question.id,)), + {'choice': 1000}) + self.assertRedirects(response, reverse('polls:detail', args=(self.question.id,))) def test_vote_without_login(self): """ Test the vote view when the user is not logged in. """ - response = self.client.post(reverse("polls:vote", args=(self.question.id,)), - {'choice' : self.choice1}) - + response = self.client.post(reverse("polls:vote", args=(self.question.id,)), + {'choice': self.choice1}) + self.assertRedirects(response, "/accounts/login/?next=/polls/1/vote/") def test_vote_voting_not_allowed(self): @@ -55,9 +56,8 @@ class VoteViewTest(TestCase): self.question_2 = create_question(question_text="Test not allow", day=10) self.choice_2 = Choice.objects.create(question=self.question_2, choice_text="Test Choice 2_2") - response = self.client.post(reverse("polls:vote", args=(self.question_2.id,)), - {"choice" : self.choice_2.id}) - + response = self.client.post(reverse("polls:vote", args=(self.question_2.id,)), {"choice": self.choice_2.id}) + self.assertRedirects(response, reverse('polls:index')) def test_vote_with_no_post_data(self): @@ -81,6 +81,6 @@ class VoteViewTest(TestCase): response_2 = self.client.post(reverse("polls:vote", args=(self.question.id,)), {"choice": self.choice2.id}) self.assertRedirects(response_2, reverse('polls:results', args=(self.question.id,))) - + self.assertFalse(Vote.objects.filter(user=self.user, question=self.question, choice=self.choice1).exists()) - self.assertTrue(Vote.objects.filter(user=self.user, question=self.question, choice=self.choice2).exists()) \ No newline at end of file + self.assertTrue(Vote.objects.filter(user=self.user, question=self.question, choice=self.choice2).exists()) diff --git a/polls/urls.py b/polls/urls.py index 7b0b4fa..8737085 100644 --- a/polls/urls.py +++ b/polls/urls.py @@ -9,6 +9,8 @@ urlpatterns = [ path("/results/", views.ResultsView.as_view(), name="results"), path("/vote/", views.vote, name="vote"), path("signup/", views.SignUpView.as_view(), name="signup"), - path("upvote/", views.up_down_vote, {'vote_type' : 'upvote'}, name="upvote"), - path("downvote/", views.up_down_vote, {'vote_type' : 'downvote'}, name="downvote"), + path("upvote/", views.up_down_vote, {'vote_type': 'upvote'}, name="upvote"), + path("downvote/", views.up_down_vote, {'vote_type': 'downvote'}, name="downvote"), + path("search", views.search_poll, name="search_poll"), + path("create", views.create_poll, name="create_poll") ] diff --git a/polls/views.py b/polls/views.py index e58f1f1..43028ae 100644 --- a/polls/views.py +++ b/polls/views.py @@ -2,7 +2,6 @@ import logging from typing import Any from django.shortcuts import get_object_or_404, render, redirect -from django.urls import reverse from django.views import generic from django.utils import timezone from django.urls import reverse_lazy, reverse @@ -12,7 +11,7 @@ from django.contrib.auth import authenticate, login from django.contrib.auth.decorators import login_required from django.db.models import Q -from .forms import SignUpForm +from .forms import SignUpForm, PollSearchForm, PollCreateForm from .models import Choice, Question, Vote @@ -26,21 +25,21 @@ class IndexView(generic.ListView): context_object_name = "latest_question_list" def get_queryset(self): - """ - Return the last published questions that is published and haven't ended yet. - """ - now = timezone.now() - all_poll_queryset = Question.objects.filter( - Q(pub_date__lte=now) & ((Q(end_date__gte=now) | Q(end_date=None))) - ).order_by("-pub_date") + """ + Return the last published questions that is published and haven't ended yet. + """ + now = timezone.now() + all_poll_queryset = Question.objects.filter( + Q(pub_date__lte=now) & ((Q(end_date__gte=now) | Q(end_date=None))) + ).order_by("-pub_date") - trend_poll_queryset = Question.objects.filter( - Q(pub_date__lte=now) & ((Q(end_date__gte=now) | Q(end_date=None))) & Q(trend_score__gte=100) - ).order_by("trend_score", "end_date")[:3] + trend_poll_queryset = Question.objects.filter( + Q(pub_date__lte=now) & ((Q(end_date__gte=now) | Q(end_date=None))) & Q(trend_score__gte=100) + ).order_by("trend_score")[:3] - queryset = {'all_poll' : all_poll_queryset, - 'trend_poll' : trend_poll_queryset,} - return queryset + queryset = {'all_poll': all_poll_queryset, + 'trend_poll': trend_poll_queryset, } + return queryset class DetailView(LoginRequiredMixin, generic.DetailView): @@ -93,12 +92,16 @@ class DetailView(LoginRequiredMixin, generic.DetailView): class ResultsView(LoginRequiredMixin, generic.DetailView): + """ + Provide a view for Result page, a Result for the poll contain poll participants + number and other statistic such as up, down vote + """ model = Question template_name = "polls/results.html" def get_context_data(self, **kwargs: Any) -> dict[str, Any]: context = super().get_context_data(**kwargs) - + user_voted = None question = self.get_object() if question.sentimentvote_set.filter(user=self.request.user, question=question, vote_types=True).exists(): @@ -109,7 +112,11 @@ class ResultsView(LoginRequiredMixin, generic.DetailView): context['user_voted'] = user_voted return context + class SignUpView(generic.CreateView): + """ + View that responsible for Sign Up page. + """ form_class = SignUpForm success_url = reverse_lazy('polls:index') template_name = 'registration/signup.html' @@ -146,7 +153,7 @@ def vote(request, question_id): vote, created = Vote.objects.update_or_create( user=request.user, question=question, - defaults={'choice' : selected_choice} + defaults={'choice': selected_choice} ) if created: @@ -163,13 +170,15 @@ def vote(request, question_id): else: messages.error(request, "Invalid request method.") return redirect("polls:index") - + @login_required def up_down_vote(request, question_id, vote_type): - ip = get_client_ip(request) + """ + A function that control the upvote and downvote request. + """ question = get_object_or_404(Question, pk=question_id) - + if request.method == "POST": if vote_type == "upvote": if question.upvote(request.user): @@ -177,15 +186,76 @@ def up_down_vote(request, question_id, vote_type): elif vote_type == "downvote": if question.downvote(request.user): messages.success(request, "You downvoted this Poll😭") - + return redirect(reverse("polls:results", args=(question_id,))) # https://stackoverflow.com/questions/4581789/how-do-i-get-user-ip-address-in-django def get_client_ip(request): + """ + Use with logger to get ip of user. + """ x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') if x_forwarded_for: ip = x_forwarded_for.split(',')[0] else: ip = request.META.get('REMOTE_ADDR') return ip + + +def search_poll(request): + """ + A function that handle the rendering of search result after user search with + search bar. + """ + form = PollSearchForm + + results = [] + q = '' + if 'q' in request.GET: + form = PollSearchForm(request.GET) + if form.is_valid(): + q = form.cleaned_data['q'] + # Case insensitive (icontains) + results = Question.objects.filter(question_text__icontains=q) + # * If user search with empty string then show every poll. + if q == '': + results = Question.objects.all() + return render(request, 'polls/search.html', {'form': form, 'results': results, 'q': q}) + + +@login_required +def create_poll(request): + ip = get_client_ip(request) + if request.method == 'POST': + form = PollCreateForm(request.POST) + if form.is_valid(): + question_text = form.cleaned_data['question_text'] + pub_date = form.cleaned_data['pub_date'] + end_date = form.cleaned_data['end_date'] + short_description = form.cleaned_data['short_description'] + long_description = form.cleaned_data.get('long_description', '') + user_choices = form.cleaned_data['user_choice'] + tags = form.cleaned_data['tags'] + + question = Question.objects.create( + question_text=question_text, + pub_date=pub_date, + end_date=end_date, + short_description=short_description, + long_description=long_description, + ) + + choices = user_choices.split(',') # Split with comma + for choice_text in choices: + Choice.objects.create(question=question, choice_text=choice_text.strip()) + + # Add tags to the question + question.tags.set(tags) + logger.info(f"User {request.user.username} ({ip}) create poll : {question_text}") + return redirect('polls:index') + + else: + form = PollCreateForm() + + return render(request, 'polls/creation.html', {'form': form}) diff --git a/setup.ps1 b/setup.ps1 index 191362c..013cc64 100644 --- a/setup.ps1 +++ b/setup.ps1 @@ -62,4 +62,5 @@ Write-Host $bottomBorder python manage.py migrate python manage.py loaddata data/users.json python manage.py loaddata data/polls.json +python manage.py loaddata data/vote.json python manage.py runserver --insecure \ No newline at end of file diff --git a/setup.py b/setup.py index 9866a7a..7b871ff 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ def check_python_command(): return command except FileNotFoundError: continue - + return None def create_virtual_environment(env_name, python_command): @@ -31,7 +31,7 @@ def customize_virtual_environment(): def setup_environment_variables(python_command_in_venv): print("Setting up Django environment variables:") - + # SECRET KEY generate_secret_key = input("Generate a Django SECRET_KEY? (yes/no): ").strip().lower() if generate_secret_key == "yes": @@ -39,7 +39,7 @@ def setup_environment_variables(python_command_in_venv): 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())']).decode().strip() else: secret_key = input("Enter Django SECRET_KEY: ").strip() - + # DEBUG MODE while True: debug_mode = input("Enable DEBUG mode? (True/False): ").strip() @@ -52,7 +52,7 @@ def setup_environment_variables(python_command_in_venv): allowed_hosts = input("Enter ALLOWED_HOSTS (comma-separated, or press Enter for default): ").strip() if not allowed_hosts: allowed_hosts = "*.ku.th,localhost,127.0.0.1,::1" - + # TZ available_time_zones = ["Asia/Bangkok", "Japan", "UCT", "CST6CDT", "Custom"] @@ -73,7 +73,7 @@ def setup_environment_variables(python_command_in_venv): print("Invalid choice. Please enter a valid number.") except ValueError: print("Invalid input. Please enter a valid number.") - + email_host_password = input("Enter EMAIL_HOST_PASSWORD: ").strip() # SET @@ -116,7 +116,7 @@ def main(): elif is_windows: activate_command = os.path.join(".venv", "Scripts", "activate") subprocess.run([activate_command], shell=True) - + python_command = os.path.join(".venv", "bin", "python") if is_posix else os.path.join(".venv", "Scripts", "python") else: print("Not setting up a virtual environment. Using the global Python interpreter.") @@ -136,6 +136,7 @@ def main(): subprocess.run([python_command, "manage.py", "migrate"]) subprocess.run([python_command, "manage.py", "loaddata", "data/users.json"]) subprocess.run([python_command, "manage.py", "loaddata", "data/polls.json"]) + subprocess.run([python_command, "manage.py", "loaddata", "data/vote.json"]) start_server = input("Do you want to start the Django server? (yes/no): ").lower() if start_server == "yes": @@ -154,19 +155,20 @@ def main(): print(f"==========================Install Requirement==========================") subprocess.run([python_command_in_venv, "-m", "pip", "install", "-r", "requirements.txt"]) setup_environment_variables(python_command_in_venv) - + subprocess.run([python_command_in_venv, "-m", "pip", "install", "-r", "requirements.txt"], check=True) subprocess.run([python_command_in_venv, "manage.py", "migrate"], check=True) subprocess.run([python_command_in_venv, "manage.py", "loaddata", "data/users.json"], check=True) subprocess.run([python_command_in_venv, "manage.py", "loaddata", "data/polls.json"], check=True) - + subprocess.run([python_command_in_venv, "manage.py", "loaddata", "data/vote.json"], check=True) + start_server = input("Do you want to start the Django server? (yes/no): ").strip().lower() if start_server == "yes": print("=================================================") print("Django run in --insecure mode to load Static File") print("==================================================") subprocess.run([python_command_in_venv, "manage.py", "runserver", "--insecure"], check=True) - + except subprocess.CalledProcessError as e: print(f"Error: {e}") sys.exit(1) @@ -174,5 +176,6 @@ def main(): print("\nSetup process aborted.") sys.exit(1) + if __name__ == "__main__": main()