Skip to content

Commit

Permalink
Merge pull request #31 from bkgoodman/master
Browse files Browse the repository at this point in the history
1.0.6
  • Loading branch information
bkgoodman authored Jul 14, 2020
2 parents e2dc6c7 + c9d9cd5 commit 1056c96
Show file tree
Hide file tree
Showing 24 changed files with 734 additions and 19 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ newexampleschema
*.swp
run_auth.py
*.sq3
authlibs/logs/static/kioskimages/*
*.acl
backups/
24 changes: 15 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ Some rough documentation as of December 2018.
`pip install google-oauth`
`sudo pip install sqlalchemy_utils`

For Covid-19 video kiosk compliance reporting script
`sudo apt install ffmpeg`

## Creating stub database

`sqlite3 makeit.db < schema.sql`
Expand Down Expand Up @@ -106,7 +109,15 @@ In a non-production enviroment, allow non-SSL OAuth with:

`python authserver.py`

This should start a server on `0.0.0.0:5000` which you can get to via browser or use the API calls. The default user/password is admin/admin (configured in .ini file).
This should start a server on `0.0.0.0:5000` which you can get to via browser or use the API calls. The default user/password is admin/admin (configured in .ini file) - but this won't be present if you're using a production database.

There are a few things you generally want to do in a local debug environment:

* In `makeit.ini` set `Deployment:` to something other than `Production` (This will make your GUI look different than production)
* In `makeit.ini` set `Logins: all`
* In `makeit.ini` set `DefaultLogin:` to `local`. THis will let you login with local credentials when `oauth` isn't working
* Do `python authserver.py --command addadmin admin admin` to add an admin account w/ password Admin (if there isn't one - like from a live database)
* Add `local.makeitlabs.com` to your `/etc/hosts` to resolve to localhost. Use that address (in we browser) to access the server. This name is whitelisted in the Oauth rules, so Oauth will be able to redirect to it (i.e. your local server)

## Fix for newer versions of Flask library

Expand All @@ -125,7 +136,6 @@ Change the import line in `authserver.py` to:
from flask_login import LoginManager, UserMixin, login_required, current_user, login_user, logout_user
```


## Using the CLI:

CLI is needed for some zero-start conditions - like assigning privilieges, or (non-oauth-login) passwords
Expand Down Expand Up @@ -155,21 +165,17 @@ You will want to run `nightly.py` on some nightly cron job. It will:

To help restore backups - you can use the `restore.py` helper script

For an example crontab - see `crontab.txt`


# Update/Deploy

### Fix wsgl config

Verify that `authserver.wsgi` is set for your appopriate deploy! (See `authserver.wsgi.EXAMPLE` for example)

### v1.0.5 Schema Update
In `makeit.ini` set a defualt door lockout message with `LockoutMessage` in the `General` section. This should not be present for normal deployments, but might want to say `Covid-19 Training Required` if appropriate.

```
begin transaction;
ALTER TABLE nodes ADD strength INTEGER;
ALTER TABLE nodes ADD last_update DATETIME;
commit;
```

### If you care about getting Slack training invites working:

Expand Down
15 changes: 15 additions & 0 deletions authlibs/api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import base64
import random,string
import tempfile
import subprocess


# You must call this modules "register_pages" with main app's "create_rotues"
blueprint = Blueprint("api", __name__, template_folder='templates', static_folder="static",url_prefix="/api")
Expand Down Expand Up @@ -378,6 +380,19 @@ def api_v1_kiosklog():

authutil.log(e,member_id=m.id,message=imagename,commit=0)
db.session.commit()
try:
cam_slackchan = current_app.config['globalConfig'].Config.get('cameras','slackchan')
s = subprocess.Popen(['/home/bkg/covid-mask-detector/covid-mask-detector/testone.py',imagecode],stdout=subprocess.PIPE)
txt = s.stdout.read().strip()
res = s.wait()
if (res != 0):
url="https://auth.makeitlabs.com"+url_for("logs.kioskentry",ke=imagecode)
res = send_slack_message(
"#project-covid-kiosk",
":alert: {0} {1} at kiosk {2}".format(m.member,txt,url)
)
except BaseException as e:
logger.error("Kiosk mask check error {0}".format(e))
try:
url=""
if imagecode:
Expand Down
4 changes: 2 additions & 2 deletions authlibs/google_user_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def google_logged_in(blueprint, token):
member=email.split("@")[0]
logger.debug("Google auth RESP for {0} {1}".format(email,member))
if not email.endswith("@makeitlabs.com"):
flash("Not a MakeIt Labs account",'warning')
flash("Not a MakeIt Labs account - You must log in with your @makeitlabs.com email address",'warning')
logger.error("Not a MakeIt Labs account "+str(email))
return redirect(url_for('empty'))
#query = Member.query.filter_by(Member.member.ilike(member))
Expand All @@ -110,7 +110,7 @@ def google_logged_in(blueprint, token):

if len(user) ==0:
flash("Error - No account found - please seek assistance",'warning')
logger.error("No account matchin %s for GUI login" % email)
logger.error("No account matching %s for GUI login" % email)
return redirect(url_for('empty'))

user = user[0]
Expand Down
3 changes: 3 additions & 0 deletions authlibs/logs/logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,9 @@ def kioskentry(ke):
ke = ke.replace("/","")
ke = ke.replace(".","")
ke = ke.replace("kioskimages:","")
if not current_user.is_arm() and (len(current_user.effective_roles()) == 0):
flash("Not authorized for this page","warning")
return redirect_url_for("index")
return render_template('kiosk_entry.html',entry=ke)

blueprint.route('/large.csv')
Expand Down
7 changes: 5 additions & 2 deletions authlibs/members/members.py
Original file line number Diff line number Diff line change
Expand Up @@ -835,8 +835,11 @@ def getDoorAccess(id):
if r:
acc = accesslib.access_query(r.id,member_id=id,tags=False)
acc = acc.first()
if not acc:
return ("No Access Record (Needs orientation?)",False,None)
if not acc:
msg = "No Access Record (Needs orientation?)"
if current_app.config['globalConfig'].Config.has_option('General','LockoutMessage'):
msg = current_app.config['globalConfig'].Config.get('General','LockoutMessage')
return (msg,False,None)
acc=accesslib.accessQueryToDict(acc)

(warning,allowed) = accesslib.determineAccess(acc,"Door access pending orientation")
Expand Down
1 change: 1 addition & 0 deletions authlibs/membership.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ def createMissingMemberAccounts(members,isTest=True,searchGoogle=False):
password = "%s%d%d" % (nameparts['last'],random.randint(1,100000),len(nameparts['last']))
try:
google.createUser(nameparts['first'],nameparts['last'],m.member,m.alt_email,password)
m.email=m.member.lower()+"@makeitlabs.com"
google.sendWelcomeEmail(m.member,password,m.alt_email)
msg = "Created new Google account for %s %s" % (m.member,m.alt_email)
logger.warn(msg)
Expand Down
7 changes: 7 additions & 0 deletions authlibs/resources/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,13 @@ def resource_showusers(resource):
(lu1,lu2,lu3) = ago.ago(mid_to_lastuse[x[1]],now)
lu2 += " ago"
sorttime = mid_to_lastuse[x[1]]
else:
# Maybe it's a door?
d = Logs.query.filter((Logs.event_type == eventtypes.RATTBE_LOGEVENT_MEMBER_ENTRY_ALLOWED.id) & (Logs.resource_id == res_id) & (Logs.member_id == x[1])).order_by(Logs.time_logged.desc()).limit(1).one_or_none()
if d:
(lu1,lu2,lu3) = ago.ago(d.time_logged,now)
lu2 += " ago"
sorttime = d.time_logged
accrec.append({'member_id':x[1],'member':x[2],'level':level,
'sortlevel':int(x[3]),
'sorttime':sorttime,
Expand Down
1 change: 1 addition & 0 deletions authlibs/resources/templates/resource_edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<div>
<div class="sectionhead"><h3>Edit Resource</h3></div>
<div class="btn-group my-2" role="group">
<a class="btn btn-outline-secondary" href="{{ url_for("resources.resource_showusers",resource=rec.name) }}" class="btn btn-link">Members</a>
<a class="btn btn-outline-secondary" href="{{ url_for("resources.resource_usage",resource=rec.name) }}" class="btn btn-link">Usage Graphs</a>
<a class="btn btn-outline-secondary" href="{{ url_for("resources.resource_usage_reports",resource=rec.name) }}" class="btn btn-link">Usage Reports</a>
<a class="btn btn-outline-secondary" href="{{ url_for("resources.maintenance",resource=rec.name) }}" class="btn btn-link">Maintenance</a>
Expand Down
2 changes: 1 addition & 1 deletion authlibs/training/training.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def training():
ar['desc'] = 'Authorization was revoked'
ar['status'] = 'cannot'
elif ma.level >0:
ar['desc'] = 'You\'r are a Resource Manager'
ar['desc'] = 'You are a Resource Manager'
ar['status'] = 'already'
else:
#User has no access - can they train?
Expand Down
75 changes: 75 additions & 0 deletions authlibs/waivers/templates/relate.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{% extends "layout_bootstrap.html" %}
{% block body %}
<p>To assign a waiver to a member - select to appropriate radio boxes for each, then click "assign"</p>
<form action="relate_assign" method="POST">
<div class=body>
<h3>Unassigned Waivers</h3>
<div class="form-row">
<div class="form-group col-md-8">
<label for="waiversearch">Search for Waiver:</label>
<input class="form-control" id="waiversearch" type="text" oninput="changedwaiversearch();" />
</div>
</div>
<h2 class="alert alert-info" id="messagebox">Enter a phrase in the search box</h2>
<table id="waiver_table" class="table table-sm bkg">
<tr>
<th>Name</th>
<th>Email</th>
<th>Created</th>
<th>Waiver ID</th>
<th>Waiver Type</th>
</tr>
{% for s in waivers %}
<tr style="visibility:collapse">
<td>{{ s.lastname }}, {{s.firstname}}</td>
<td>{{ s.email }}</td>
<td>{{ s.created_date }}</td>
<td>{{ s.waiver_id }}</td>
{% if s.waivertype in waiverTypes %}
<td>{{ waiverTypes[s.waivertype] }}</td>
{% else %}
<td>???</td>
{% endif %}
<td><input type="radio" name="do_waiver" value="assign:{{ s.waiver_id }}">&nbsp;Assign to...</input></td>
</tr>
{% endfor %}
</table>
<input type="submit" class="btn btn-primary" value="Assign" name="Assign" />
</div>
<hr />
<h3>Attach to Member:</h4>
<div class="container">
{% with add_radiobuttons=1 %}
{% include 'userlist.html' %}
{% endwith %}
</div>
</form>
<script type="text/javascript">
function changedwaiversearch() {
r = document.getElementById("waiversearch").value.toLowerCase();
console.log(r);
table = document.getElementById("waiver_table");
table.visibility="";
msg = document.getElementById("messagebox");
if (r.length >= 3) {
table.visibility="";
msg.style.display="none";
for (var i = 0, row; row = table.rows[i]; i++) {
row.style.visibility="collapse";
if (row.cells[0].innerHTML.toLowerCase().includes(r))
row.style.visibility="";
if (row.cells[1].innerHTML.toLowerCase().includes(r))
row.style.visibility="";
if (row.cells[3].innerHTML.toLowerCase().includes(r))
row.style.visibility="";
//iterate through rows
//rows would be accessed using the "row" variable assigned in the for loop
//console.log(row.cells[1].innerHTML);
}
} else {
msg.style.display="block";
table.visibility="collapse";
}
}
</script>
{% endblock %}
3 changes: 2 additions & 1 deletion authlibs/waivers/templates/waivers.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
<div class=body>
<div class="sectionhead">Waiver Data</div>
{% if current_user.privs("Useredit") or current_user.privs("Finance") %}
<a href="{{ url_for('waivers.waivers_update') }}">Update Waiver Data (May take a while)</a>
<a class="btn btn-primary" href="{{ url_for('waivers.waivers_update') }}">Update Waiver Data (May take a while)</a>
<a class="btn btn btn-primary" href="{{ url_for('waivers.relate') }}">Assign Waivers</a>
{% endif %}
<p></p>
Show Waivers: <select id="filterSelect" onChange="changeFilter();">
Expand Down
60 changes: 59 additions & 1 deletion authlibs/waivers/waivers.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,15 +147,73 @@ def connect_waivers():
if len(m)==1:
w.member_id = m[0].id
s += " accept waiver for member %s" % m[0].member
try:
comment = Waiver.waiverTypes[w.waivertype]['short']
except:
comment="??"
authutil.log(eventtypes.RATTBE_LOGEVENT_MEMBER_WAIVER_ACCEPTED.id,member_id=m[0].id,message=comment,commit=0)
if (w.waivertype == Waiver.WAIVER_TYPE_MEMBER):
if (m[0].access_reason is None or m[0].access_reason == ""):
m[0].access_enabled=1;
authutil.log(eventtypes.RATTBE_LOGEVENT_MEMBER_WAIVER_ACCEPTED.id,member_id=m[0].id,commit=0)
authutil.log(eventtypes.RATTBE_LOGEVENT_MEMBER_ACCESS_ENABLED.id,member_id=m[0].id,commit=0)
else:
authutil.log(eventtypes.RATTBE_LOGEVENT_MEMBER_ACCESS_DISABLED.id,message="Waiver found, but access otherwise denied",member_id=m[0].id,commit=0)
#else:
# print s+" ?? len "+str(len(m))
db.session.commit()

@blueprint.route('/relate', methods = ['GET'])
@login_required
@roles_required(['Admin','Finance','Useredit'])
def relate():
mem=None
if 'member_id' in request.values:
mid = int(request.values['member_id'])
mem = Member.query.filter(Member.id==mid).one_or_none()
waivers = Waiver.query.filter(Subscription.member_id == None).all()

wt ={}
for w in Waiver.waiverTypes:
wt[w['code']]=w['short']
return render_template('relate.html',waivers=waivers,linkmember=mem,waiverTypes=wt)

# Post handler for "relate" above
@blueprint.route('/relate_assign', methods = ['POST'])
@login_required
@roles_required(['Admin','Finance','Useredit'])
def relate_assign():
if 'Assign' in request.form:
if 'do_waiver' not in request.form:
flash ("Choose a waiver to \"Assign To\" this member","warning")
return redirect(url_for('waivers.relate',member_id=linkmemberid))
(action,waiverid) = request.form['do_waiver'].split(":",1)
if action == "assign" and 'member_radio' not in request.form:
flash ("You must (search for and select) a Member to Assign a waiver to","warning")
return redirect(url_for('waivers.relate'))

if action == "assign":
mem = Member.query.filter(Member.member == request.form['member_radio']).one()
wall = Waiver.query.filter(Waiver.waiver_id == waiverid).all()
if len(wall) == 0:
flash ("Waiver {0} not found".format(waiverid))
else:
for w in wall:
w.member_id = mem.id
try:
comment = Waiver.waiverTypes[w.waivertype]['short']
except:
comment="??"
authutil.log(eventtypes.RATTBE_LOGEVENT_MEMBER_WAIVER_ACCEPTED.id,member_id=mem.id,doneby=current_user.id,message=comment,commit=0)
if (w.waivertype == Waiver.WAIVER_TYPE_MEMBER):
if (mem.access_reason is None or mem.access_reason == ""):
mem.access_enabled=1;
authutil.log(eventtypes.RATTBE_LOGEVENT_MEMBER_ACCESS_ENABLED.id,member_id=mem.id,commit=0)
db.session.commit()
flash ("Assigning waiver to existing member","success")
else:
flash("No action specified","warning")

return redirect(url_for('waivers.relate'))

def cli_waivers_connect(*cmd,**kvargs):
connect_waivers()
Loading

0 comments on commit 1056c96

Please sign in to comment.