Compare commits
56 commits
testbranch
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 62e307f6a2 | |||
| cf4b642461 | |||
| 1d313233a6 | |||
| 4aca571930 | |||
| 88ad7d4908 | |||
| 12777b49a4 | |||
| 959c98fe79 | |||
| d2a04f8b5a | |||
| 82cd51b805 | |||
| ba10625f3d | |||
| 90c0f3ae98 | |||
| d6c532ea49 | |||
| 2d3c542b32 | |||
| 7ada4b2a6f | |||
| 93dd70849a | |||
| c86acc10ca | |||
| fde7fdd50a | |||
| 96c553fd36 | |||
| 3f0c84566e | |||
| b225349931 | |||
| 460a9a06cd | |||
| 879dda4891 | |||
| b6a8c6c53b | |||
| f4d5e0a690 | |||
| fc90674ccc | |||
| fdcdcf1c4c | |||
| a4661a1e0b | |||
| 33cfbbcc9f | |||
| 45e9b3a9bc | |||
| ab8e276db8 | |||
| 8a3d082458 | |||
| 57c0e317cc | |||
| 816c1d697e | |||
| 5582af5ee7 | |||
| 0b78e121a2 | |||
| 39e5127f3f | |||
| d3d53b434f | |||
| 42f76f1987 | |||
| bdde079e43 | |||
| 528d62010b | |||
| 0b17e39074 | |||
| d0908cf65d | |||
| fbdc6b4ee4 | |||
| 450b06c185 | |||
| bdf909c143 | |||
| 25bafd04e0 | |||
| 2ca4812480 | |||
| 71d1910988 | |||
| 67264b3da6 | |||
| 936a88f264 | |||
| f20458ae1c | |||
| 300331b2f2 | |||
| 0b1fde2066 | |||
| b186239f04 | |||
| 359d7e8c81 | |||
| a608576bc5 |
51 changed files with 948 additions and 59 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,4 +1,5 @@
|
|||
/__pycache__
|
||||
**/__pycache__
|
||||
/errorlog.txt
|
||||
/instance
|
||||
/logs.log
|
||||
|
|
|
|||
|
|
@ -32,10 +32,15 @@ def create_app():
|
|||
app.wsgi_app, x_for=1, x_proto=1
|
||||
)
|
||||
|
||||
from app.users.models import User
|
||||
import app.users.models as user_models
|
||||
import app.campaigns.models as campaign_models
|
||||
import app.main.models as main_models
|
||||
|
||||
|
||||
|
||||
@login_manager.user_loader
|
||||
def load_user(user_id):
|
||||
user = User.query.get(user_id)
|
||||
user = user_models.User.query.get(user_id)
|
||||
if user:
|
||||
return user
|
||||
else:
|
||||
|
|
@ -43,17 +48,22 @@ def create_app():
|
|||
login_manager.login_view = 'users.login'
|
||||
|
||||
from app.users import users
|
||||
from app.users.users_api import users_api
|
||||
from app.main import main
|
||||
from app.campaigns import campaigns
|
||||
from app.campaigns.campaign_api import campaign_api
|
||||
from app.admin import admin
|
||||
# from app.agent_reports import agent_reports
|
||||
# from app.status_reports import status_reports
|
||||
from app.arba_yesodot import arba_yesodot
|
||||
|
||||
campaigns.register_blueprint(campaign_api)
|
||||
users.register_blueprint(users_api)
|
||||
|
||||
app.register_blueprint(users)
|
||||
app.register_blueprint(main)
|
||||
app.register_blueprint(campaigns)
|
||||
app.register_blueprint(admin)
|
||||
# app.register_blueprint(agent_reports)
|
||||
# app.register_blueprint(status_reports)
|
||||
app.register_blueprint(arba_yesodot)
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def reroute_base_url():
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,6 +1,8 @@
|
|||
from app import db
|
||||
from app.admin import admin
|
||||
from app.users.models import User
|
||||
from app.campaigns.models import Campaign
|
||||
from app.main.models import Donation
|
||||
from app.users.forms import LoginForm, RegisterUserForm#, RequestResetForm, ResetPasswordForm, EditUserForm, AddUserForm
|
||||
from flask import render_template, redirect, url_for, flash, request
|
||||
from flask_login import login_required, login_user, current_user, logout_user
|
||||
|
|
@ -10,4 +12,14 @@ import os
|
|||
|
||||
@admin.route('administration')
|
||||
def administration():
|
||||
return render_template('administration.html')
|
||||
users = User.query.all()
|
||||
campaigns = Campaign.query.filter_by(archived=False).all()
|
||||
return render_template('administration.html',
|
||||
users=users,
|
||||
campaigns=campaigns)
|
||||
|
||||
@admin.route('archive')
|
||||
def archive():
|
||||
archived_campaigns = Campaign.query.filter_by(archived=True).all()
|
||||
return render_template('archive.html',
|
||||
archived_campaigns=archived_campaigns)
|
||||
98
app/admin/static/admin.js
Normal file
98
app/admin/static/admin.js
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
const archiveButtons = document.getElementsByClassName('archive-button');
|
||||
const activityButtons = document.getElementsByClassName('change-activity-btn');
|
||||
const adminButtons = document.getElementsByClassName('change-admin-btn');
|
||||
|
||||
|
||||
function deactivateAdminButtons(){
|
||||
for (let i = 0; i < adminButtons.length; i++){
|
||||
adminButtons[i].disabled=true;
|
||||
}
|
||||
}
|
||||
function activateAdminButtons(){
|
||||
for (let i = 0; i < adminButtons.length; i++){
|
||||
adminButtons[i].disabled=false;
|
||||
}
|
||||
}
|
||||
function deactivateArchiveButtons(){
|
||||
for (let i = 0; i < archiveButtons.length; i++){
|
||||
archiveButtons[i].disabled=true;
|
||||
}
|
||||
}
|
||||
function activateArchiveButtons(){
|
||||
for (let i = 0; i < archiveButtons.length; i++){
|
||||
archiveButtons[i].disabled=false;
|
||||
}
|
||||
}
|
||||
function deactivateActiveStatusCheckboxes(){
|
||||
for (let i = 0; i < activityButtons.length; i++){
|
||||
activityButtons[i].disabled=true;
|
||||
}
|
||||
}
|
||||
function activateActiveStatusCheckboxes(){
|
||||
for (let i = 0; i < activityButtons.length; i++){
|
||||
activityButtons[i].disabled=false;
|
||||
}
|
||||
}
|
||||
|
||||
function activateAllButtons(){
|
||||
activateAdminButtons()
|
||||
activateArchiveButtons()
|
||||
activateActiveStatusCheckboxes()
|
||||
}
|
||||
function deactivateAllButtons(){
|
||||
deactivateAdminButtons()
|
||||
deactivateArchiveButtons()
|
||||
deactivateActiveStatusCheckboxes()
|
||||
}
|
||||
|
||||
async function updateActiveStatus(id, status) {
|
||||
deactivateAllButtons()
|
||||
var result = await fetch(`/campaigns/campaign_api/update_active_status/${id}/${status}`, {method:'PUT'});
|
||||
var data = await result.json();
|
||||
if (status === true){
|
||||
status = 'True'
|
||||
} else {
|
||||
status = 'False'
|
||||
}
|
||||
document.getElementById(`${id}-active-status`).innerText = status;
|
||||
activateAllButtons()
|
||||
}
|
||||
|
||||
async function archiveCampaign(id){
|
||||
deactivateAllButtons()
|
||||
var result = await fetch(`/campaigns/campaign_api/archive_campaign/${id}`, {method:'PUT'});
|
||||
var data = await result.json();
|
||||
document.getElementById(`${id}-row`).remove();
|
||||
activateAllButtons()
|
||||
}
|
||||
|
||||
async function updateAdminStatus(id, status) {
|
||||
deactivateAllButtons()
|
||||
var result = await fetch(`/users/users_api/update_admin_status/${id}/${status}`, {method:'PUT'});
|
||||
var data = await result.json();
|
||||
if (status === true){
|
||||
status = 'True'
|
||||
} else {
|
||||
status = 'False'
|
||||
}
|
||||
document.getElementById(`${id}-admin-status`).innerText = status;
|
||||
activateAllButtons()
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", (event) => {
|
||||
for(let i = 0; i < activityButtons.length; i++){
|
||||
activityButtons[i].addEventListener('change', e => {
|
||||
updateActiveStatus(parseInt(e.target.value), e.target.checked)
|
||||
})
|
||||
}
|
||||
for(let i = 0; i < archiveButtons.length; i++){
|
||||
archiveButtons[i].addEventListener('click', e => {
|
||||
archiveCampaign(parseInt(e.target.value))
|
||||
})
|
||||
}
|
||||
for(let i = 0; i < adminButtons.length; i++){
|
||||
adminButtons[i].addEventListener('change', e => {
|
||||
updateAdminStatus(parseInt(e.target.value), e.target.checked)
|
||||
})
|
||||
}
|
||||
});
|
||||
56
app/admin/static/administration.css
Normal file
56
app/admin/static/administration.css
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
height: 34px;
|
||||
}
|
||||
.switch input {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 26px;
|
||||
width: 26px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: white;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
input:checked + .slider {
|
||||
background-color: #2196F3;
|
||||
}
|
||||
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px #2196F3;
|
||||
}
|
||||
|
||||
input:checked + .slider:before {
|
||||
-webkit-transform: translateX(26px);
|
||||
-ms-transform: translateX(26px);
|
||||
transform: translateX(26px);
|
||||
}
|
||||
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 34px;
|
||||
}
|
||||
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
31
app/admin/static/archive.js
Normal file
31
app/admin/static/archive.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
const unArchiveButtons = document.getElementsByClassName('unarchive-button');
|
||||
|
||||
|
||||
function deactivateUnArchiveButtons(){
|
||||
for (let i = 0; i < unArchiveButtons.length; i++){
|
||||
unArchiveButtons[i].disabled=true;
|
||||
}
|
||||
}
|
||||
function activateUnArchiveButtons(){
|
||||
for (let i = 0; i < unArchiveButtons.length; i++){
|
||||
unArchiveButtons[i].disabled=false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function unArchiveCampaign(id){
|
||||
deactivateUnArchiveButtons()
|
||||
var result = await fetch(`/campaigns/campaign_api/un_archive_campaign/${id}`, {method:'PUT'});
|
||||
var data = await result.json();
|
||||
document.getElementById(`${id}-row`).remove();
|
||||
activateUnArchiveButtons()
|
||||
}
|
||||
|
||||
|
||||
document.addEventListener("DOMContentLoaded", (event) => {
|
||||
for(let i = 0; i < unArchiveButtons.length; i++){
|
||||
unArchiveButtons[i].addEventListener('click', e => {
|
||||
unArchiveCampaign(parseInt(e.target.value))
|
||||
})
|
||||
}
|
||||
});
|
||||
|
|
@ -1,2 +1,90 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block title %}Administration{% endblock title %}
|
||||
{% block title %}Administration{% endblock title %}
|
||||
{% block stylesheet %}
|
||||
<link rel="stylesheet" href="{{ url_for('admin.static', filename='administration.css') }}">
|
||||
{% endblock stylesheet %}
|
||||
{% block content %}
|
||||
<main>
|
||||
<div class="container my-4 px-5">
|
||||
<h2 class="text-center">Users</h2>
|
||||
|
||||
<table class="table table-bordered table-striped">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>First Name</th>
|
||||
<th>Last Name</th>
|
||||
<th>Email</th>
|
||||
<th>Is Admin?</th>
|
||||
<th>Change Admin Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in users %}
|
||||
<tr>
|
||||
<td>{{user.id}}</td>
|
||||
<td>{{user.first_name}}</td>
|
||||
<td>{{user.last_name}}</td>
|
||||
<td>{{user.email}}</td>
|
||||
<td id="{{user.id}}-admin-status">{% if user.user_type == 'Admin' %}True{%else%}False{%endif%}</td>
|
||||
<td>
|
||||
<label class="switch">
|
||||
<input
|
||||
type="checkbox"
|
||||
value="{{user.id}}"
|
||||
id="admin-checkbox-{{user.id}}"
|
||||
class="change-admin-btn"
|
||||
{%if user.user_type == 'Admin'%}checked{%endif%}>
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="container my-4 px-5">
|
||||
<div class="d-flex justify-content-center align-items-center">
|
||||
<h2 class="me-3">Campaigns</h2>
|
||||
<a href="{{url_for('campaigns.add_campaign')}}" class="btn btn-primary">New Campaign</a>
|
||||
</div>
|
||||
<table class="table table-bordered table-striped">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Title</th>
|
||||
<th>Active</th>
|
||||
<th>Change Active Status</th>
|
||||
<th>Archive?</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for campaign in campaigns %}
|
||||
<tr id="{{campaign.id}}-row" >
|
||||
<td>{{campaign.id}}</td>
|
||||
<td>{{campaign.title}}</td>
|
||||
<td id="{{campaign.id}}-active-status">{{campaign.active}}</td>
|
||||
<td>
|
||||
<label class="switch">
|
||||
<input
|
||||
type="checkbox"
|
||||
value="{{campaign.id}}"
|
||||
id="active-checkbox-{{campaign.id}}"
|
||||
class="change-activity-btn"
|
||||
{%if campaign.active%}checked{%endif%}>
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</td>
|
||||
<td><button
|
||||
id="archive-button-{{campaign.id}}"
|
||||
value="{{campaign.id}}"
|
||||
class="archive-button btn btn-primary">Click to archive</button></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</main>
|
||||
<script src="{{url_for('.static', filename='admin.js')}}"></script>
|
||||
{% endblock content %}
|
||||
|
|
|
|||
38
app/admin/templates/archive.html
Normal file
38
app/admin/templates/archive.html
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block title %}Archive{% endblock title %}
|
||||
{% block stylesheet %}{% endblock stylesheet %}
|
||||
{% block content %}
|
||||
<main>
|
||||
<div class="container my-4 px-5">
|
||||
<h2 class="text-center">Archived Campaigns</h2>
|
||||
|
||||
<table class="table table-bordered table-striped custom-table">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
<th>Goal</th>
|
||||
<th>Raised</th>
|
||||
<th>Campaign Link</th>
|
||||
<th>Unarchive?</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for campaign in archived_campaigns %}
|
||||
<tr id="{{campaign.id}}-row">
|
||||
<td>{{campaign.title}}</td>
|
||||
<td>{{campaign.goal}}</td>
|
||||
<td>{{campaign.get_amount_raised()}}</td>
|
||||
<td><a href="{{url_for('campaigns.campaign_page', campaign_id=campaign.id)}}">See campaign details</a></td>
|
||||
<td><button
|
||||
id="unarchive-button-{{campaign.id}}"
|
||||
value="{{campaign.id}}"
|
||||
class="unarchive-button btn btn-primary">Click to un-archive</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</main>
|
||||
<script src="{{url_for('.static', filename='archive.js')}}"></script>
|
||||
{% endblock content %}
|
||||
9
app/arba_yesodot/__init__.py
Normal file
9
app/arba_yesodot/__init__.py
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
from flask import Blueprint
|
||||
|
||||
arba_yesodot = Blueprint('arba_yesodot',
|
||||
__name__,
|
||||
template_folder='templates',
|
||||
static_folder='static',
|
||||
url_prefix='/arba_yesodot')
|
||||
|
||||
from app.arba_yesodot import routes
|
||||
15
app/arba_yesodot/routes.py
Normal file
15
app/arba_yesodot/routes.py
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
from app import db
|
||||
from app.arba_yesodot import arba_yesodot
|
||||
from app.users.models import User
|
||||
from app.campaigns.models import Campaign
|
||||
from app.campaigns.forms import CreateCampaignForm
|
||||
from flask import render_template, redirect, url_for, flash, request
|
||||
from flask_login import login_required, login_user, current_user, logout_user
|
||||
from werkzeug.security import check_password_hash, generate_password_hash
|
||||
from datetime import datetime
|
||||
import os
|
||||
from time import sleep
|
||||
|
||||
@arba_yesodot.route('arba_yesodot_homepage')
|
||||
def arba_yesodot_homepage():
|
||||
return render_template('arba_yesodot_homepage.html')
|
||||
6
app/arba_yesodot/templates/arba_yesodot_homepage.html
Normal file
6
app/arba_yesodot/templates/arba_yesodot_homepage.html
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block title %}Arba Yesodot{% endblock title %}
|
||||
{% block stylesheet %}{% endblock stylesheet %}
|
||||
{% block content %}
|
||||
|
||||
{% endblock content %}
|
||||
Binary file not shown.
Binary file not shown.
9
app/campaigns/campaign_api/__init__.py
Normal file
9
app/campaigns/campaign_api/__init__.py
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
from flask import Blueprint
|
||||
|
||||
campaign_api = Blueprint('campaign_api',
|
||||
__name__,
|
||||
template_folder='templates',
|
||||
static_folder='static',
|
||||
url_prefix='/campaign_api')
|
||||
|
||||
from app.campaigns.campaign_api import routes
|
||||
30
app/campaigns/campaign_api/routes.py
Normal file
30
app/campaigns/campaign_api/routes.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
from app import db
|
||||
from flask import render_template
|
||||
from app.campaigns.campaign_api import campaign_api
|
||||
from app.campaigns.models import Campaign
|
||||
from time import sleep
|
||||
|
||||
|
||||
|
||||
@campaign_api.route('update_active_status/<id>/<status>', methods=['PUT'])
|
||||
def update_active_status(id, status):
|
||||
if status == 'true':
|
||||
status = True
|
||||
else:
|
||||
status = False
|
||||
Campaign.query.filter_by(id=id).update({'active':status})
|
||||
db.session.commit()
|
||||
sleep(1)
|
||||
return {'status':'success'}
|
||||
|
||||
@campaign_api.route('archive_campaign/<id>', methods=['PUT'])
|
||||
def archive_campaign(id):
|
||||
Campaign.query.filter_by(id=id).update({'archived': True, 'active':False})
|
||||
db.session.commit()
|
||||
return {'status':'success'}
|
||||
|
||||
@campaign_api.route('un_archive_campaign/<id>', methods=['PUT'])
|
||||
def un_archive_campaign(id):
|
||||
Campaign.query.filter_by(id=id).update({'archived': False, 'active':False})
|
||||
db.session.commit()
|
||||
return {'status':'success'}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, \
|
||||
EmailField, \
|
||||
PasswordField, \
|
||||
SubmitField, \
|
||||
SelectField, \
|
||||
BooleanField,\
|
||||
DateField, IntegerField
|
||||
from flask_wtf.file import FileField, FileRequired, FileAllowed
|
||||
from wtforms.validators import DataRequired, ValidationError, NumberRange, EqualTo, Email
|
||||
from app.campaigns.models import Campaign
|
||||
from flask_login import current_user
|
||||
# import logging
|
||||
# logging.basicConfig(filename='logs.log', encoding='utf-8', level=logging.DEBUG)
|
||||
|
||||
class CreateCampaignForm(FlaskForm):
|
||||
title = StringField('Title', validators=[DataRequired()])
|
||||
active = BooleanField('Initialize as active?')
|
||||
goal = IntegerField('Goal')
|
||||
submit = SubmitField('Add Campaign')
|
||||
|
|
@ -6,9 +6,37 @@ import jwt
|
|||
from datetime import datetime, timezone, timedelta
|
||||
|
||||
|
||||
class AmbassadorMap(db.Model):
|
||||
__tablename__ = 'ambassador_map'
|
||||
id = Column('id', INTEGER(), primary_key=True)
|
||||
campaign_id = Column('campaign_id', INTEGER(), nullable=False)
|
||||
user_id = Column('user_id', INTEGER(), nullable=False)
|
||||
goal = Column('ambassador_goal', INTEGER())
|
||||
|
||||
|
||||
|
||||
class Campaign(db.Model):
|
||||
__tablename__ = 'campaign'
|
||||
id = Column('id', INTEGER(), primary_key=True)
|
||||
title = Column('title', TEXT(), nullable=False)
|
||||
#ambassadors
|
||||
id = Column('id', INTEGER(), primary_key=True)
|
||||
title = Column('title', TEXT(), nullable=False)
|
||||
active = Column('active', Boolean(), nullable=False, default=True)
|
||||
goal = Column('goal', INTEGER(), default=0)
|
||||
archived = Column('archived', Boolean(), default=False)
|
||||
|
||||
def get_donations(self):
|
||||
from app.main.models import Donation
|
||||
return Donation.query.filter_by(campaign_id=self.id).all()
|
||||
|
||||
def get_amount_raised(self):
|
||||
donations = self.get_donations()
|
||||
total = 0
|
||||
for donation in donations:
|
||||
total += donation.amount
|
||||
return total
|
||||
|
||||
def get_ambassadors(self):
|
||||
return AmbassadorMap.query.filter_by(campaign_id=self.id).all()
|
||||
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"{self.id} - {self.title}"
|
||||
|
|
@ -1,13 +1,36 @@
|
|||
from app import db
|
||||
from app.campaigns import campaigns
|
||||
from app.users.models import User
|
||||
# from forms import LoginForm, RequestResetForm, ResetPasswordForm, EditUserForm, AddUserForm
|
||||
from app.campaigns.models import Campaign
|
||||
from app.campaigns.forms import CreateCampaignForm
|
||||
from flask import render_template, redirect, url_for, flash, request
|
||||
from flask_login import login_required, login_user, current_user, logout_user
|
||||
from werkzeug.security import check_password_hash, generate_password_hash
|
||||
from datetime import datetime
|
||||
import os
|
||||
from time import sleep
|
||||
|
||||
@campaigns.route('add_campaign')
|
||||
@campaigns.route('add_campaign', methods=['GET', 'POST'])
|
||||
def add_campaign():
|
||||
return render_template('add_campaign.html')
|
||||
form = CreateCampaignForm()
|
||||
if form.validate_on_submit():
|
||||
campaign = Campaign(
|
||||
title=form.title.data,
|
||||
active=form.active.data,
|
||||
goal=form.goal.data
|
||||
)
|
||||
db.session.add(campaign)
|
||||
db.session.commit()
|
||||
return redirect(url_for('admin.administration'))
|
||||
return render_template('add_campaign.html',
|
||||
form=form)
|
||||
|
||||
@campaigns.route('campaign_page/<campaign_id>')
|
||||
def campaign_page(campaign_id):
|
||||
campaign = Campaign.query.filter_by(id=campaign_id).first()
|
||||
return render_template('campaign_page.html',
|
||||
campaign=campaign)
|
||||
|
||||
@campaigns.route('add_ambassador')
|
||||
def add_ambassador():
|
||||
return render_template('add_ambassador.html')
|
||||
0
app/campaigns/templates/add_ambassador.html
Normal file
0
app/campaigns/templates/add_ambassador.html
Normal file
|
|
@ -1,2 +1,56 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block title %}Add campaign{% endblock title %}
|
||||
{% block title %}Add campaign{% endblock title %}
|
||||
{% block content %}
|
||||
<main class="container-lg mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Register</h3>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
<div class="mb-3">
|
||||
{{ form.title.label(class="form-label") }}
|
||||
{{ form.title(class="form-control") }}
|
||||
{% if form.title.errors %}
|
||||
<ul class="errors">
|
||||
{% for error in form.title.errors %}
|
||||
<li>{{ error }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
{{ form.active.label(class="form-label") }}
|
||||
{{ form.active() }}
|
||||
{% if form.active.errors %}
|
||||
<ul class="errors">
|
||||
{% for error in form.active.errors %}
|
||||
<li>{{ error }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
{{ form.goal.label(class="form-label") }}
|
||||
{{ form.goal(class="form-control") }}
|
||||
{% if form.goal.errors %}
|
||||
<ul class="errors">
|
||||
{% for error in form.goal.errors %}
|
||||
<li>{{ error }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{{ form.submit(class='btn btn-primary') }}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
{% endblock content %}
|
||||
62
app/campaigns/templates/campaign_page.html
Normal file
62
app/campaigns/templates/campaign_page.html
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block title %}{{campaign.title}}{% endblock title %}
|
||||
{% block content %}
|
||||
<main class="container-lg mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-5">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-center align-items-center">
|
||||
<h2 class="text-center">{{campaign.title}} Ambassadors</h2>
|
||||
<a href="{{url_for('campaigns.add_ambassador')}}" class="btn btn-primary">Become an ambassador!</a>
|
||||
</div>
|
||||
<table class="table table-bordered table-striped">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Goal</th>
|
||||
<th>Ambassador Page Link</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for campaign_ambassador in campaign.get_ambassadors() %}
|
||||
<tr>
|
||||
<td>{{campaign_ambassador.user_id}}</td>
|
||||
<td>{{campaign_ambassador.goal}}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h2 class="text-center">{{campaign.title}}</h2>
|
||||
|
||||
<table class="table table-bordered table-striped">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Amount</th>
|
||||
<th>User</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for campaign_donation in campaign.get_donations() %}
|
||||
<tr>
|
||||
<td>{{campaign_donation.id}}</td>
|
||||
<td>{{campaign_donation.amount}}</td>
|
||||
<td>{{campaign_donation.get_user()}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
{% endblock content %}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
23
app/main/models.py
Normal file
23
app/main/models.py
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
from app import db
|
||||
from flask import current_app
|
||||
from flask_login import UserMixin, current_user
|
||||
from sqlalchemy import TEXT, Column, Boolean, ForeignKey, TEXT, INTEGER, VARCHAR
|
||||
import jwt
|
||||
from datetime import datetime, timezone, timedelta
|
||||
|
||||
|
||||
class Donation(db.Model):
|
||||
__tablename__ = 'donation'
|
||||
id = Column('id', INTEGER(), primary_key=True, autoincrement=True)
|
||||
currency_type = Column('currency_type', TEXT(), nullable=False)
|
||||
amount = Column('amount', INTEGER(), nullable=False)
|
||||
user_id = Column('user_id', INTEGER(), nullable=False)
|
||||
campaign_id = Column('campaign_id', INTEGER(), nullable=False)
|
||||
anonymous = Column('anonymous', Boolean(), default=False)
|
||||
|
||||
def get_user(self):
|
||||
from app.users.models import User
|
||||
return User.query.filter_by(id=self.user_id).first()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"{self.id} - {self.currency_type} - {self.amount}"
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
from app import db
|
||||
from app.main import main
|
||||
from app.users.models import User
|
||||
from app.campaigns.models import Campaign
|
||||
# from forms import LoginForm, RequestResetForm, ResetPasswordForm, EditUserForm, AddUserForm
|
||||
from flask import render_template, redirect, url_for, flash, request
|
||||
from flask_login import login_required, login_user, current_user, logout_user
|
||||
|
|
@ -12,6 +13,7 @@ import os
|
|||
|
||||
|
||||
@main.route('/homepage')
|
||||
def homepage():
|
||||
|
||||
return render_template('homepage.html')
|
||||
def homepage():
|
||||
active_campaigns = Campaign.query.filter_by(active=True).all()
|
||||
return render_template('homepage.html',
|
||||
active_campaigns=active_campaigns)
|
||||
0
app/main/static/main.css
Normal file
0
app/main/static/main.css
Normal file
|
|
@ -14,18 +14,19 @@
|
|||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<a href="{{url_for('main.homepage')}}" style="text-decoration: none; margin-right: 10px;"><p>Pilzno</p></a>
|
||||
{% if current_user.is_authenticated %}
|
||||
<a href="{{url_for('users.user_page', user_id=current_user.id)}}" style="text-decoration: none;"><span class="navbar-brand">User Page</span></a>
|
||||
{% if current_user.user_type == 'Admin' %}
|
||||
<a href="{{url_for('admin.administration')}}" style="text-decoration: none;"><span class="navbar-brand">Admin Management</span></a>
|
||||
{% endif %}
|
||||
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
|
||||
<div class="navbar-nav">
|
||||
<a class="nav-item nav-link active" href="{{url_for('users.logout')}}">Logout</a>
|
||||
</div>
|
||||
</div>
|
||||
<a href="{{url_for('users.user_page', user_id=current_user.id)}}" style="text-decoration: none;"><span class="navbar-brand">User Page</span></a>
|
||||
{% if current_user.user_type == 'Admin' %}
|
||||
<a href="{{url_for('admin.administration')}}" style="text-decoration: none;"><span class="navbar-brand">Admin Management</span></a>
|
||||
<a href="{{url_for('admin.archive')}}" style="text-decoration: none;"><span class="navbar-brand">Archive</span></a>
|
||||
{% endif %}
|
||||
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
|
||||
<div class="navbar-nav">
|
||||
<a class="nav-item nav-link active" href="{{url_for('users.logout')}}">Logout</a>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<a href="{{url_for('users.login')}}" style="text-decoration: none;"><span class="navbar-brand">Login</span></a>
|
||||
<a href="{{url_for('users.register_user')}}" style="text-decoration: none;"><span class="navbar-brand">Register</span></a>
|
||||
<a href="{{url_for('users.login')}}" style="text-decoration: none;"><span class="navbar-brand">Login</span></a>
|
||||
<a href="{{url_for('users.register_user')}}" style="text-decoration: none;"><span class="navbar-brand">Register</span></a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
|
|
|
|||
|
|
@ -1,2 +1,44 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block title %}Customer Search{% endblock title %}
|
||||
{% block title %}Homepage{% endblock title %}
|
||||
|
||||
{% block stylesheet %}
|
||||
<style>
|
||||
.custom-table {
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
overflow: hidden; /* Ensures rounded corners apply to the entire table */
|
||||
}
|
||||
</style>
|
||||
{% endblock stylesheet %}
|
||||
{% block content %}
|
||||
<main>
|
||||
<div class="container my-4 px-5">
|
||||
<div class="text-center mb-4">
|
||||
<a href="{{ url_for('arba_yesodot.arba_yesodot_homepage') }}" class="btn btn-primary">Check out the arba yesodot program!</a>
|
||||
</div>
|
||||
<h2 class="text-center">Visit Campaigns</h2>
|
||||
|
||||
<table class="table table-bordered table-striped custom-table">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
<th>Goal</th>
|
||||
<th>Raised</th>
|
||||
<th>Campaign Link</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for campaign in active_campaigns %}
|
||||
<tr>
|
||||
<td>{{campaign.title}}</td>
|
||||
<td>{{campaign.goal}}</td>
|
||||
<td>{{campaign.get_amount_raised()}}</td>
|
||||
<td><a href="{{url_for('campaigns.campaign_page', campaign_id=campaign.id)}}">See campaign details</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
{% endblock content %}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,7 +1,7 @@
|
|||
from app import db
|
||||
from flask import current_app
|
||||
from flask_login import UserMixin, current_user
|
||||
from sqlalchemy import TEXT, Column, Boolean, ForeignKey, TEXT, INTEGER, VARCHAR
|
||||
from sqlalchemy import TEXT, Column, Boolean, ForeignKey, TEXT, INTEGER, VARCHAR, select
|
||||
import jwt
|
||||
from datetime import datetime, timezone, timedelta
|
||||
|
||||
|
|
@ -14,6 +14,14 @@ class User(db.Model, UserMixin):
|
|||
email = Column('email', TEXT(), nullable=False, unique=True)
|
||||
password = Column('password', TEXT(), nullable=False)
|
||||
user_type = Column('user_type', TEXT(), nullable=False)
|
||||
|
||||
def get_donations(self):
|
||||
from app.main.models import Donation
|
||||
return db.session.execute(select(Donation.currency_type,Donation.amount).where(Donation.user_id == self.id)).all()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"{self.first_name} {self.last_name}"
|
||||
# donation_id = Column(INTEGER, ForeignKey('donation.id'))
|
||||
|
||||
def get_reset_token(self, expiration=600):
|
||||
reset_token = jwt.encode(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
from app import db
|
||||
from app.users import users
|
||||
from app.users.models import User
|
||||
from app.campaigns.models import Campaign
|
||||
from app.main.models import Donation
|
||||
from app.users.forms import LoginForm, RegisterUserForm#, RequestResetForm, ResetPasswordForm, EditUserForm, AddUserForm
|
||||
from flask import render_template, redirect, url_for, flash, request
|
||||
from flask_login import login_required, login_user, current_user, logout_user
|
||||
|
|
@ -15,17 +17,19 @@ import os
|
|||
@login_required
|
||||
def user_page(user_id):
|
||||
if not int(current_user.id) == int(user_id):
|
||||
return redirect(url_for('main.dashboard'))
|
||||
return redirect(url_for('main.homepage'))
|
||||
user = User.query.filter_by(id=user_id).first()
|
||||
donations = user.get_donations()
|
||||
return render_template('user_page.html',
|
||||
user=user)
|
||||
user=user,
|
||||
donations=donations)
|
||||
|
||||
|
||||
@users.route('/')
|
||||
@users.route('/login', methods=('GET', 'POST'))
|
||||
def login():
|
||||
if current_user.is_authenticated:
|
||||
return redirect(url_for('main.dashboard'))
|
||||
return redirect(url_for('main.homepage'))
|
||||
form = LoginForm()
|
||||
if form.validate_on_submit():
|
||||
user = User.query.filter_by(email=form.email.data).first()
|
||||
|
|
@ -66,4 +70,4 @@ def register_user():
|
|||
login_user(user)
|
||||
flash('Succesfully Registered!')
|
||||
return redirect(url_for('main.homepage'))
|
||||
return render_template('register_user.html', form=form)
|
||||
return render_template('register_user.html', form=form)
|
||||
|
|
|
|||
|
|
@ -1,38 +1,40 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block title %}User Page{% endblock title %}
|
||||
{% block content %}
|
||||
<main class="container">
|
||||
<main class="container-lg mt-5">
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-6 offset-md-3">
|
||||
<h1>Welcome, {{ user.first_name }} {{ user.last_name }}</h1>
|
||||
<hr>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-5">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-center align-items-center">
|
||||
<h2 class="text-center">Donations</h2>
|
||||
</div>
|
||||
<table class="table table-bordered table-striped">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>Currency</th>
|
||||
<th>Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for donation in donations %}
|
||||
<tr>
|
||||
<td>{{donation[0]}}</td>
|
||||
<td>{{donation[1]}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-10 offset-md-1">
|
||||
{% if user_reports %}
|
||||
<h2>Downloadable Files:</h2>
|
||||
<table class="table mt-3">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Report Type</th>
|
||||
<th>Number of Rows</th>
|
||||
<th>Time Created</th>
|
||||
<th>Range Start</th>
|
||||
<th>Range End</th>
|
||||
<th>Download</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p>No reports available.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{% endblock %}
|
||||
9
app/users/users_api/__init__.py
Normal file
9
app/users/users_api/__init__.py
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
from flask import Blueprint
|
||||
|
||||
users_api = Blueprint('users_api',
|
||||
__name__,
|
||||
template_folder='templates',
|
||||
static_folder='static',
|
||||
url_prefix='/users_api')
|
||||
|
||||
from app.users.users_api import routes
|
||||
18
app/users/users_api/routes.py
Normal file
18
app/users/users_api/routes.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
from app import db
|
||||
from flask import render_template
|
||||
from app.users.users_api import users_api
|
||||
from app.users.models import User
|
||||
from time import sleep
|
||||
|
||||
|
||||
|
||||
@users_api.route('update_admin_status/<id>/<status>', methods=['PUT'])
|
||||
def update_admin_status(id, status):
|
||||
if status == 'true':
|
||||
status = 'Admin'
|
||||
else:
|
||||
status = 'User'
|
||||
User.query.filter_by(id=id).update({'user_type':status})
|
||||
db.session.commit()
|
||||
sleep(1)
|
||||
return {'status':'success'}
|
||||
151
python_files/db_population.py
Normal file
151
python_files/db_population.py
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
from sqlalchemy import create_engine, MetaData, Table, select, insert, func, update, bindparam, delete
|
||||
import os
|
||||
import csv
|
||||
from datetime import datetime, timedelta
|
||||
from dateutil.parser import parse
|
||||
import time
|
||||
import json
|
||||
from werkzeug.security import generate_password_hash
|
||||
import random
|
||||
|
||||
def engineer():
|
||||
path1 = 'C:/Users/Lenovo/Desktop/Pilzno/instance/site.db'
|
||||
path2 = '/home/yisroel2/Desktop/Pilzno/instance/site.db'
|
||||
path3 = '/home/ubuntu/PilznoProject/PilznoProduction/instance/site.db'
|
||||
|
||||
for p in [path1, path2, path3]:
|
||||
if os.path.exists(p):
|
||||
path = p
|
||||
break
|
||||
engine = create_engine(f'sqlite:///{path}')
|
||||
metadata_obj = MetaData()
|
||||
metadata_obj.reflect(bind=engine)
|
||||
return engine, metadata_obj
|
||||
|
||||
def check_db():
|
||||
engine, metadata_obj = engineer()
|
||||
user_table = Table("user", metadata_obj, autoload_with=engine)
|
||||
donation_table = Table("donation", metadata_obj, autoload_with=engine)
|
||||
campaign_table = Table("campaign", metadata_obj, autoload_with=engine)
|
||||
with engine.connect() as conn:
|
||||
print('USERS')
|
||||
users = conn.execute(select(user_table)).all()
|
||||
if users:
|
||||
for user in users:
|
||||
print(user.first_name)
|
||||
else:
|
||||
print('no users')
|
||||
print("DONATIONS")
|
||||
donations = conn.execute(select(donation_table)).all()
|
||||
if donations:
|
||||
for donation in donations:
|
||||
print(donation.id)
|
||||
else:
|
||||
print('no donations')
|
||||
campaigns = conn.execute(select(campaign_table)).all()
|
||||
print('CAMPAIGNS')
|
||||
if campaigns:
|
||||
for campaign in campaigns:
|
||||
print(campaign.title)
|
||||
else:
|
||||
print('no campaigns')
|
||||
|
||||
def insert_users():
|
||||
users = [
|
||||
['Yisroel', 'Baum', 'yisroel.d.baum@gmail.com', generate_password_hash('12'), 'Admin'],
|
||||
['Yoni', 'Gerzi', 'yoni@gerzi.com', generate_password_hash('12'), 'User'],
|
||||
['Shmuli', 'Modes', 'shmuli@modes.com', generate_password_hash('12'), 'User'],
|
||||
['Emma', 'Baum', 'emma@baum.com', generate_password_hash('12'), 'User'],
|
||||
['Yisroel', 'Factor', 'yisroel@factor.com', generate_password_hash('12'), 'User'],
|
||||
['Yaakov', 'Frager', 'yaakov@frager.com', generate_password_hash('12'), 'User'],
|
||||
['Michael', 'Oshman', 'michael@oshman.com', generate_password_hash('12'), 'User'],
|
||||
['Shalom', 'Goldberg', 'shalom@goldberg.com', generate_password_hash('12'), 'User'],
|
||||
['Daniel', 'Caller', 'daniel@caller.com', generate_password_hash('12'), 'User'],
|
||||
|
||||
]
|
||||
engine, metadata_obj = engineer()
|
||||
user_table = Table("user", metadata_obj, autoload_with=engine)
|
||||
|
||||
with engine.connect() as conn:
|
||||
for user in users:
|
||||
conn.execute(user_table.insert().values(
|
||||
first_name = user[0],
|
||||
last_name = user[1],
|
||||
email = user[2],
|
||||
password = user[3],
|
||||
user_type = user[4]
|
||||
))
|
||||
conn.commit()
|
||||
|
||||
def insert_donations():
|
||||
engine, metadata_obj = engineer()
|
||||
donation_table = Table("donation", metadata_obj, autoload_with=engine)
|
||||
|
||||
currency_types = ['shekel', 'dollar']
|
||||
boolean_choice = [True, False]
|
||||
|
||||
with engine.connect() as conn:
|
||||
for _ in range(100):
|
||||
conn.execute(donation_table.insert().values(
|
||||
currency_type = currency_types[random.randint(0,1)],
|
||||
amount = random.randint(1,200),
|
||||
anonymous = boolean_choice[random.randint(0,1)],
|
||||
campaign_id=random.randint(1,4),
|
||||
user_id=random.randint(1,9)
|
||||
))
|
||||
conn.commit()
|
||||
|
||||
def insert_campaigns():
|
||||
engine, metadata_obj = engineer()
|
||||
campaign_table = Table("campaign", metadata_obj, autoload_with=engine)
|
||||
|
||||
campaign_titles = ['general campaign', 'yomim noraim 2024', 'pesach kibbudim 2024', 'RH kibbudim 2024']
|
||||
is_active = [True, False]
|
||||
with engine.connect() as conn:
|
||||
for title in campaign_titles:
|
||||
conn.execute(campaign_table.insert().values(
|
||||
title=title,
|
||||
active=is_active[random.randint(0,1)],
|
||||
goal=5000,
|
||||
archived=False
|
||||
))
|
||||
conn.commit()
|
||||
|
||||
def insert_ambassador_relationships():
|
||||
engine, metadata_obj = engineer()
|
||||
user_table = Table("user", metadata_obj, autoload_with=engine)
|
||||
donation_table = Table("donation", metadata_obj, autoload_with=engine)
|
||||
campaign_table = Table("campaign", metadata_obj, autoload_with=engine)
|
||||
|
||||
with engine.connect() as conn:
|
||||
campaign_ids = conn.execute(select(campaign_table.c.id)).all()
|
||||
user_ids = conn.execute(select(user_table.c.id)).all()
|
||||
|
||||
|
||||
def test_selections():
|
||||
engine, metadata_obj = engineer()
|
||||
user_table = Table("user", metadata_obj, autoload_with=engine)
|
||||
donation_table = Table("donation", metadata_obj, autoload_with=engine)
|
||||
campaign_table = Table("campaign", metadata_obj, autoload_with=engine)
|
||||
|
||||
|
||||
def delete_all():
|
||||
engine, metadata_obj = engineer()
|
||||
user_table = Table("user", metadata_obj, autoload_with=engine)
|
||||
donation_table = Table("donation", metadata_obj, autoload_with=engine)
|
||||
campaign_table = Table("campaign", metadata_obj, autoload_with=engine)
|
||||
|
||||
with engine.connect() as conn:
|
||||
conn.execute(delete(user_table))
|
||||
conn.execute(delete(campaign_table))
|
||||
conn.execute(delete(donation_table))
|
||||
conn.commit()
|
||||
|
||||
def insert_all():
|
||||
insert_users()
|
||||
insert_campaigns()
|
||||
insert_donations()
|
||||
|
||||
if __name__ == '__main__':
|
||||
delete_all()
|
||||
insert_all()
|
||||
39
requirements.txt
Normal file
39
requirements.txt
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
alembic==1.13.2
|
||||
amqp==5.2.0
|
||||
billiard==4.2.0
|
||||
blinker==1.8.2
|
||||
celery==5.4.0
|
||||
cffi==1.17.0
|
||||
click==8.1.7
|
||||
click-didyoumean==0.3.1
|
||||
click-plugins==1.1.1
|
||||
click-repl==0.3.0
|
||||
colorama==0.4.6
|
||||
cryptography==43.0.1
|
||||
dnspython==2.6.1
|
||||
email_validator==2.2.0
|
||||
Flask==3.0.3
|
||||
Flask-Login==0.6.3
|
||||
Flask-Mail==0.10.0
|
||||
Flask-Migrate==4.0.7
|
||||
Flask-SQLAlchemy==3.1.1
|
||||
Flask-WTF==1.2.1
|
||||
greenlet==3.0.3
|
||||
idna==3.8
|
||||
itsdangerous==2.2.0
|
||||
Jinja2==3.1.4
|
||||
jwt==1.3.1
|
||||
kombu==5.4.0
|
||||
Mako==1.3.5
|
||||
MarkupSafe==2.1.5
|
||||
prompt_toolkit==3.0.47
|
||||
pycparser==2.22
|
||||
python-dateutil==2.9.0.post0
|
||||
six==1.16.0
|
||||
SQLAlchemy==2.0.33
|
||||
typing_extensions==4.12.2
|
||||
tzdata==2024.1
|
||||
vine==5.1.0
|
||||
wcwidth==0.2.13
|
||||
Werkzeug==3.0.4
|
||||
WTForms==3.1.2
|
||||
Loading…
Add table
Add a link
Reference in a new issue