Searching, sorting, and updating users #36
					 2 changed files with 114 additions and 5 deletions
				
			
		| 
						 | 
					@ -4,6 +4,8 @@ from flask_mail import Message
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from goathacks.models import User
 | 
					from goathacks.models import User
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from sqlalchemy.exc import IntegrityError
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bp = Blueprint("admin", __name__, url_prefix="/admin")
 | 
					bp = Blueprint("admin", __name__, url_prefix="/admin")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from goathacks import db, mail as app_mail
 | 
					from goathacks import db, mail as app_mail
 | 
				
			||||||
| 
						 | 
					@ -221,6 +223,44 @@ def hackers():
 | 
				
			||||||
    users = User.query.all()
 | 
					    users = User.query.all()
 | 
				
			||||||
    return User.create_json_output(users)
 | 
					    return User.create_json_output(users)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@bp.route("/updateHacker", methods=["POST"])
 | 
				
			||||||
 | 
					@login_required
 | 
				
			||||||
 | 
					def updateHacker():
 | 
				
			||||||
 | 
					    if not current_user.is_admin:
 | 
				
			||||||
 | 
					        return redirect(url_for("dashboard.home"))
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    # get params from json
 | 
				
			||||||
 | 
					    hacker_id = request.json['hacker_id']
 | 
				
			||||||
 | 
					    change_field = request.json['change_field']
 | 
				
			||||||
 | 
					    new_val = request.json['new_val']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # find the user in db
 | 
				
			||||||
 | 
					    user = User.query.filter_by(id=hacker_id).one()
 | 
				
			||||||
 | 
					    if user is None:
 | 
				
			||||||
 | 
					        return {"status": "error", "msg": "user not found"}
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # update the hacker depending on change_field
 | 
				
			||||||
 | 
					    match change_field:
 | 
				
			||||||
 | 
					        case "first_name":
 | 
				
			||||||
 | 
					            user.first_name = new_val
 | 
				
			||||||
 | 
					        case "last_name":
 | 
				
			||||||
 | 
					            user.last_name = new_val
 | 
				
			||||||
 | 
					        case "school":
 | 
				
			||||||
 | 
					            user.school = new_val
 | 
				
			||||||
 | 
					        case "phone":
 | 
				
			||||||
 | 
					            user.phone = new_val
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        db.session.commit()
 | 
				
			||||||
 | 
					    except IntegrityError as err:
 | 
				
			||||||
 | 
					        db.session.rollback()
 | 
				
			||||||
 | 
					        flash("Could not update user information for user " + hacker_id)
 | 
				
			||||||
 | 
					        return {"status": "error"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    return {"status": "success"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
import csv
 | 
					import csv
 | 
				
			||||||
from io import StringIO
 | 
					from io import StringIO
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,8 +14,22 @@
 | 
				
			||||||
{% block app_content %}
 | 
					{% block app_content %}
 | 
				
			||||||
<div class="card text-center">
 | 
					<div class="card text-center">
 | 
				
			||||||
    <div class="card-body">
 | 
					    <div class="card-body">
 | 
				
			||||||
        <h1 class="h3 mb-3 fw-normal">Registered Users</h1>
 | 
					
 | 
				
			||||||
        <table id="hackers" class="table table-striped">
 | 
					        <div style="display:flex;flex-wrap:nowrap;align-items:center;">
 | 
				
			||||||
 | 
					            <div class="dropdown">
 | 
				
			||||||
 | 
					                <a href="#" class="btn btn-primary dropdown-toggle"
 | 
				
			||||||
 | 
					                            data-bs-toggle="dropdown">Search<span
 | 
				
			||||||
 | 
					                            class="caret"></span></a>
 | 
				
			||||||
 | 
					                <ul class="dropdown-menu">
 | 
				
			||||||
 | 
					                    <input style="padding:5px;margin-left:10px;margin-right:10px;" type="text" id="searchbox" name="searchbox-text" placeholder="Search By Email" onkeyup="filterHackers()"/>
 | 
				
			||||||
 | 
					                </ul>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <!-- TODO: get "Registered Users" properly centered -->
 | 
				
			||||||
 | 
					            <h1 style="flex-grow:1;justify-content:center;" class="h3 mb-3 fw-normal">Registered Users</h1>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <table id="hackers" class="table table-striped sortable">
 | 
				
			||||||
            <thead>
 | 
					            <thead>
 | 
				
			||||||
                <tr>
 | 
					                <tr>
 | 
				
			||||||
                    <th>Options</th>
 | 
					                    <th>Options</th>
 | 
				
			||||||
| 
						 | 
					@ -79,16 +93,71 @@
 | 
				
			||||||
                    <td>{{ hacker.id }}</td>
 | 
					                    <td>{{ hacker.id }}</td>
 | 
				
			||||||
                    <td>{{ hacker.last_login }}</td>
 | 
					                    <td>{{ hacker.last_login }}</td>
 | 
				
			||||||
                    <td>{{ hacker.email }}</td>
 | 
					                    <td>{{ hacker.email }}</td>
 | 
				
			||||||
                    <td>{{ hacker.first_name + ' ' + hacker.last_name }}</td>
 | 
					                    <td>
 | 
				
			||||||
                    <td>{{ hacker.phone }}</td>
 | 
					                        <div style="display: flex; justify-content: flex-start;">
 | 
				
			||||||
 | 
					                            <input style="padding:5px; margin-left:10px; margin-right:10px;width:fit-content;max-width:100px;" type="text" id="{{hacker.id}}-namebox-first" placeholder="first_name" value="{{hacker.first_name}}" onchange="updateHacker(this.id, 'first_name', this.value)"/>
 | 
				
			||||||
 | 
					                            <input style="padding:5px; margin-left:10px; margin-right:10px;width:fit-content;max-width:100px;" type="text" id="{{hacker.id}}-namebox-last" placeholder="last_name" value="{{hacker.last_name}}" onchange="updateHacker(this.id, 'last_name', this.value)"/>
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					                    </td>
 | 
				
			||||||
 | 
					                    <td>
 | 
				
			||||||
 | 
					                        <input style="padding:5px; margin-left:10px; margin-right:10px;width:fit-content;max-width:100px;" type="text" id="{{hacker.id}}-phonebox" placeholder="phone" value="{{hacker.phone}}" onchange="updateHacker(this.id, 'phone', this.value)"/>
 | 
				
			||||||
 | 
					                    </td>
 | 
				
			||||||
                    <td>{{ hacker.shirt_size }}</td>
 | 
					                    <td>{{ hacker.shirt_size }}</td>
 | 
				
			||||||
                    <td>{{ hacker.accomodations }}</td>
 | 
					                    <td>{{ hacker.accomodations }}</td>
 | 
				
			||||||
                    <td>{{ hacker.school }}</td>
 | 
					                    <td>
 | 
				
			||||||
 | 
					                        <input style="padding:5px; margin-left:10px; margin-right:10px;width:fit-content;max-width:75px;" type="text" id="{{hacker.id}}-schoolbox" placeholder="school" value="{{hacker.school}}" onchange="updateHacker(this.id, 'school', this.value)"/>
 | 
				
			||||||
 | 
					                    </td>
 | 
				
			||||||
                </tr>
 | 
					                </tr>
 | 
				
			||||||
                {% endfor %}
 | 
					                {% endfor %}
 | 
				
			||||||
            </tbody>
 | 
					            </tbody>
 | 
				
			||||||
        </table>
 | 
					        </table>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script type="text/javascript">
 | 
				
			||||||
 | 
					    function filterHackers() {
 | 
				
			||||||
 | 
					        //get hacker table and searchbox info
 | 
				
			||||||
 | 
					        const input = document.getElementById("searchbox").value.toLowerCase();
 | 
				
			||||||
 | 
					        const hackertable = document.getElementById("hackers");
 | 
				
			||||||
 | 
					        let rows = hackertable.getElementsByTagName("tr");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //iterate over all rows
 | 
				
			||||||
 | 
					        for(let i = 1; i < rows.length; i++) {
 | 
				
			||||||
 | 
					            //get the email
 | 
				
			||||||
 | 
					            const cells = rows[i].getElementsByTagName("td");
 | 
				
			||||||
 | 
					            const emailCell = cells[6];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //if there is an email, display or dont display based on searchbox
 | 
				
			||||||
 | 
					            if(emailCell) {
 | 
				
			||||||
 | 
					                const emailText = emailCell.textContent.toLowerCase();
 | 
				
			||||||
 | 
					                if(!emailText.includes(input)) {
 | 
				
			||||||
 | 
					                    rows[i].style.display = "none";
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else {
 | 
				
			||||||
 | 
					                    rows[i].style.display = "";
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function updateHacker(id, change_field, new_val) {
 | 
				
			||||||
 | 
					        //tell backend to update a specific field for a hacker
 | 
				
			||||||
 | 
					        const headers = [
 | 
				
			||||||
 | 
					            ["Content-Type", "application/json"],
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let body = {
 | 
				
			||||||
 | 
					            "hacker_id": id.substr(0, id.indexOf('-')),
 | 
				
			||||||
 | 
					            "change_field": change_field,
 | 
				
			||||||
 | 
					            "new_val": new_val,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //send the post request, and report the error if there is one
 | 
				
			||||||
 | 
					        fetch('/admin/updateHacker', {method: 'POST', body: JSON.stringify(body), headers: headers}).catch((err) => {
 | 
				
			||||||
 | 
					            window.alert("Error updating user - see console for details");
 | 
				
			||||||
 | 
					            console.log(err);
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue