Skip to content
17 changes: 13 additions & 4 deletions ocfweb/account/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,21 @@ def commands(request: HttpRequest) -> HttpResponse:
ssh = SSHClient()

host_keys = ssh.get_host_keys()
entry = HostKeyEntry.from_line(
entry_ed25519 = HostKeyEntry.from_line(
'ssh.ocf.berkeley.edu ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPm+RlDujsxQyxFTEOCTeImSBDvr63cL8Kg+rNrH6NK8', # noqa
)
entry_rsa = HostKeyEntry.from_line(
'ssh.ocf.berkeley.edu ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAqMkHVVoMl8md25iky7e2Xe3ARaC4H1PbIpv5Y+xT4KOT17gGvFSmfjGyW9P8ZTyqxq560iWdyELIn7efaGPbkUo9retcnT6WLmuh9nRIYwb6w7BGEEvlblBmH27Fkgt7JQ6+1sr5teuABfIMg22WTQAeDQe1jg0XsPu36OjbC7HjA3BXsiNBpxKDolYIXWzOD+r9FxZLP0lawh8dl//O5FW4ha1IbHklq2i9Mgl79wAH3jxf66kQJTvLmalKnQ0Dbp2+vYGGhIjVFXlGSzKsHAVhuVD6TBXZbxWOYoXanS7CC43MrEtBYYnc6zMn/k/rH0V+WeRhuzTnr/OZGJbBBw==', # noqa
)
assert entry is not None # should never be none as we are passing a static string above
host_keys.add(
'ssh.ocf.berkeley.edu',
'ssh-ed25519',
entry_ed25519.key,
)
host_keys.add(
'ssh.ocf.berkeley.edu',
'ssh-rsa',
entry.key,
entry_rsa.key,
)

try:
Expand All @@ -45,6 +52,8 @@ def commands(request: HttpRequest) -> HttpResponse:
error = 'Authentication failed. Did you type the wrong username or password?'

if not error:
if command_to_run == 'paper':
command_to_run = f"/run/current-system/sw/bin/paper view {username} | sed 's/\x1B\\[[0-9;]*[a-zA-Z]//g'" # noqa
_, ssh_stdout, ssh_stderr = ssh.exec_command(command_to_run, get_pty=True)
output = ssh_stdout.read().decode()
error = ssh_stderr.read().decode()
Expand Down Expand Up @@ -78,7 +87,7 @@ class CommandForm(Form):

COMMAND_CHOICES = (
(
'/opt/share/utils/bin/paper',
'paper',
'paper quota -- how many pages you have remaining this semester',
),
(
Expand Down
101 changes: 101 additions & 0 deletions ocfweb/account/info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
from django import forms
from django.http import HttpRequest
from django.http import HttpResponse
from django.shortcuts import render
from ocflib.printing.quota import get_connection
from ocflib.printing.quota import get_quota
from ocflib.vhost.application import get_app_vhosts
from ocflib.vhost.mail import vhosts_for_user
from ocflib.vhost.web import get_vhosts
from paramiko import AuthenticationException
from paramiko import SSHClient
from paramiko.hostkeys import HostKeyEntry

from ocfweb.auth import login_required
from ocfweb.component.forms import Form
from ocfweb.component.session import logged_in_user


@login_required
def account_info(request: HttpRequest) -> HttpResponse:
user = logged_in_user(request)
# user = 'animage' # test
with get_connection() as c:
paper_quota = get_quota(c, user)
bytes_used = None
bytes_total = None
error = ''
if request.method == 'POST':
form = PasswordForm(request.POST)
if form.is_valid():
password = form.cleaned_data['password']
ssh = SSHClient()
host_keys = ssh.get_host_keys()
entry_ed25519 = HostKeyEntry.from_line(
'ssh.ocf.berkeley.edu ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPm+RlDujsxQyxFTEOCTeImSBDvr63cL8Kg+rNrH6NK8', # noqa
)
entry_rsa = HostKeyEntry.from_line(
'ssh.ocf.berkeley.edu ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAqMkHVVoMl8md25iky7e2Xe3ARaC4H1PbIpv5Y+xT4KOT17gGvFSmfjGyW9P8ZTyqxq560iWdyELIn7efaGPbkUo9retcnT6WLmuh9nRIYwb6w7BGEEvlblBmH27Fkgt7JQ6+1sr5teuABfIMg22WTQAeDQe1jg0XsPu36OjbC7HjA3BXsiNBpxKDolYIXWzOD+r9FxZLP0lawh8dl//O5FW4ha1IbHklq2i9Mgl79wAH3jxf66kQJTvLmalKnQ0Dbp2+vYGGhIjVFXlGSzKsHAVhuVD6TBXZbxWOYoXanS7CC43MrEtBYYnc6zMn/k/rH0V+WeRhuzTnr/OZGJbBBw==', # noqa
)
host_keys.add(
'ssh.ocf.berkeley.edu',
'ssh-ed25519',
entry_ed25519.key,
)
host_keys.add(
'ssh.ocf.berkeley.edu',
'ssh-rsa',
entry_rsa.key,
)

try:
ssh.connect(
'ssh.ocf.berkeley.edu',
username=user,
password=password,
)
except AuthenticationException:
error = 'Authentication failed. Did you type the wrong password?'

if not error:
quota_command = "/run/current-system/sw/bin/quota 2>/dev/null | awk 'NR==4 {print $1, $2}'"
_, ssh_stdout, _ = ssh.exec_command(quota_command, get_pty=True)
sizes = ssh_stdout.read().decode().split()
if len(sizes) == 2:
bytes_used, bytes_total = (int(size) * 1024 for size in sizes)
else:
error = 'Unable to get quota information from the server. Please try again later.'
else:
form = PasswordForm()

return render(
request,
'account/info/index.html', {
'title': 'My Account',
'form': form,
'error': error,
'paper_quota': paper_quota,
'bytes_used': bytes_used,
'bytes_total': bytes_total,
'vhosts': [
{'host': host, 'aliases': val['aliases']}
for host, val in get_vhosts().items()
if val['username'] == user
],
'vhosts_app': [
{'host': host, 'aliases': val['aliases']}
for host, val in get_app_vhosts().items()
if val['username'] == user
],
'vhosts_mail': vhosts_for_user(user),
},
)


class PasswordForm(Form):
password = forms.CharField(
widget=forms.PasswordInput,
label='',
min_length=8,
max_length=256,
)
75 changes: 75 additions & 0 deletions ocfweb/account/templates/account/info/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{% extends "base.html" %}
{% load bootstrap %}

{% block content %}
<div class="row">
<div class="col-md-8 ocf-content-block">
<p>You are logged in as <strong>{{user}}</strong>, which is {{ user_is_group|yesno:"a group,an individual" }} account.</p>
{% if user_is_group %}
<p>Group accounts can't print. Sorry!</p>
{% else %}
<p>You currently have:</p>
<ul>
<li><span class="semibold">{{paper_quota.daily}} sides</span> of paper left for printing today</li>
<li><span class="semibold">{{paper_quota.semesterly}} sides</span> left for the semester</li>
<li><span class="semibold">{{paper_quota.color}} sides</span> left for color printing this semester</li>
</ul>
{% endif %}
{% if bytes_used is None %}
<p>Please re-enter your OCF password to check your personal storage.</p>
<form action="{% url 'account_info' %}" method="post" class="form-mini">
{% csrf_token %}
{{form | bootstrap}}
<input class="btn btn-primary" type="submit" value="Submit" />
</form>
{% if error %}
<p><strong>{{ error }}</strong></p>
{% endif %}
{% else %}
<p>You have used <span class="semibold">{{ bytes_used|filesizeformat }}</span> out of {{ bytes_total|filesizeformat }} available in disk storage on the OCF servers.</p>
{% endif %}
{% if user_is_group or vhosts or vhosts_app or vhosts_mail %}
{% if vhosts %}
<p>Your account has web virtual hosting at:</p>
<ul>
{% for vhost in vhosts %}
<li><code>{{vhost.host}}</code>{% if vhost.aliases %} with alias{{ vhost.aliases|pluralize:"es" }} {% for vhost_alias in vhost.aliases %} <code>{{vhost_alias}}</code>{% endfor %}{% endif %}</li>
{% endfor %}
</ul>
{% else %}
<p>Your account is not yet set up for web virtual hosting.</p>
{% endif %}
{% if vhosts_app %}
<p>Your account has web application hosting at:</p>
<ul>
{% for vhost_app in vhosts_app %}
<li><code>{{vhost_app.host}}</code>{% if vhost_app.aliases %} with alias{{ vhost_app.aliases|pluralize:"es" }} {% for vhost_app_alias in vhost_app.aliases %} <code>{{vhost_app_alias}}</code>{% endfor %}{% endif %}</li>
{% endfor %}
</ul>
{% else %}
<p>Your account is not yet set up for web application hosting.</p>
{% endif %}
{% if vhosts_mail %}
<p>Your account has mail virtual hosting at:</p>
<ul>
{% for vhost_mail in vhosts_mail %}
<li><code>{{vhost_mail.domain}}</code></li>
{% endfor %}
</ul>
{% else %}
<p>Your account is not yet set up for mail virtual hosting.</p>
{% endif %}
{% else %}
<p>Only group, faculty, and staff accounts are eligible for virtual hosting. Sorry!</p>
{% endif %}
<p>You can also check this information via <a href="{{docs_url}}/user-docs/services/shell/">SSH</a> by running <code>paper view {{user}}</code>, <code>quota -vs</code>, and <code>check {{user}}</code>.</p>
<p>For our policies on printing, file storage, and virtual hosting, refer to the relevant documentation:</p>
<ul>
<li><a href="{{docs_url}}/user-docs/services/lab/printing/">Printing</a></li>
<li><a href="{{docs_url}}/user-docs/services/shell/#disk-quotas">Disk storage</a></li>
<li><a href="{{docs_url}}/user-docs/services/vhost/">Virtual hosting</a></li>
</ul>
<p>Out of pages? Here's a <a href="{{docs_url}}/user-docs/services/lab/printing/#out-of-pages">suggested list</a> of other places to print on and around campus.</p>
</div>
</div>
{% endblock %}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
<p>
You already have an OCF account! Your username is
<strong>{{account}}</strong>. If you can't remember your password,
you can reset it <a href="{% url 'change_password' %}">here</a>.
you can reset it <a href="{% url 'change_password' %}">here</a>. Otherwise, you can <a href="{% url 'login' %}">log in</a> to access your OCF account.
</p>
<p>If you believe this is an error, please <a href="{% url 'doc' 'contact' %}">
contact us</a> with your CalNet UID: <tt>{{calnet_uid}}</tt>.

<p>Please logout <a href="{% url 'calnet_logout' %}" id="calnet_url">here</a>.</p>
<p>If you are not signing into the OCF, please log out of CalNet <a href="{% url 'calnet_logout' %}" id="calnet_url">here</a>.</p>
</div>
{% endblock %}
2 changes: 1 addition & 1 deletion ocfweb/account/templates/account/register/success.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{% block content %}
<div class="ocf-content-block">
<p>Your account has successfully been created!</p>
<p>You can start using any of our <a href="{% url 'doc' 'services' %}">services</a>. Watch out for an email from us with more information!</p>
<p>You can start using any of our <a href="{{docs_url}}/user-docs/services/">services</a>. Watch out for an email from us with more information!</p>
<p>Thanks for flying OCF!</p>
</div>
{% endblock %}
2 changes: 2 additions & 0 deletions ocfweb/account/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from ocfweb.account.chpass import change_password
from ocfweb.account.commands import commands
from ocfweb.account.info import account_info
from ocfweb.account.register import account_created
from ocfweb.account.register import account_pending
from ocfweb.account.register import recommend
Expand All @@ -19,6 +20,7 @@
urlpatterns = [
re_path(r'^password/$', change_password, name='change_password'),
re_path(r'^commands/$', commands, name='commands'),
re_path(r'^info/$', account_info, name='account_info'),

# account creation
re_path(r'^register/$', request_account, name='register'),
Expand Down
10 changes: 7 additions & 3 deletions ocfweb/main/templates/main/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ <h1>Welcome to the Open Computing Facility!</h1>
<p>The Open Computing Facility (OCF) is an all-volunteer student organization dedicated to free computing for all University of California, Berkeley students, faculty, and staff.</p>
<p>We're passionate about open source and free software.</p>
<p class="ocf-button-holder">
<a href="{% url 'about-staff' %}" class="btn btn-lg">Learn what we do</a>
<a href="{% url 'register' %}" class="btn btn-lg">Create an account</a>
<a href="{% url 'about-staff' %}" class="btn btn-lg">Learn what we do</a>
{% if user %}
<a href="{% url 'account_info' %}" class="btn btn-lg">View my account</a>
{% else %}
<a href="{% url 'register' %}" class="btn btn-lg">Create an account</a>
{% endif %}
</p>
</div>
</div>
Expand All @@ -39,7 +43,7 @@ <h1>Welcome to the Open Computing Facility!</h1>
<li><a href="{{docs_url}}/user-docs/services/hpc/">High-performance computing</a> on our GPU server</li>
<li>...and <a href="{{docs_url}}/user-docs/services">lots more!</a></li>
</ul>
<p>Check out upcoming events on the <a href="{{docs_url}}/news/">OCF Newsletter</a>.</p>
<p>Check out upcoming events on the <a href="https://ocf.io/gcal">OCF calendar</a>.</p>
<p>We hold <a href="{% url 'staff-hours' %}">weekly staff hours</a> to provide assistance with account issues or with OCF services. Drop by to ask questions or just to hang out!</p>

<hr />
Expand Down
4 changes: 4 additions & 0 deletions ocfweb/main/templates/main/lab.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
<a href="{{ docs_url }}/user-docs/services/lab/printing">Printing</a>.
</p>

<p>
If you'd like to reserve the lab space for your organization's event, please review our
<a href="https://ocf.io/reserve">reservation policy</a> and submit a request in the linked form.
</p>

<h2 id="location">Location</h2>
<p>
Expand Down
27 changes: 24 additions & 3 deletions ocfweb/static/scss/site.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,24 @@
$screen-lg-min: 1200px
*/

$color-blue-baby: #cbe1ea;
$color-blue-baby: #c1e4f0;
$color-blue-light: #f8fcfc;
$color-blue: #298399;
$color-gray-light: #ccc;
$color-gray: #aaa;
$color-green-light: #de9;
$color-purple-light: #e5e7f0;
$color-yellow-light: #ffc;
$color-penguin-blue: #0f4d92;
$color-penguin-yellow: #ffd700;

$navbar-height: 60px;

$hero-color: $color-green-light;
$hero-color: $color-blue-baby;
$hero-button-color: #f7f7f7;
$hero-button-color-hover: #fff;

$status-bar-color: $color-blue-baby;
$status-bar-color: $color-purple-light;

$footer-top-color: $color-gray-light;
$footer-bottom-color: $color-gray;
Expand Down Expand Up @@ -70,6 +71,26 @@ code {
font-family: 'IBM Plex Mono', Menlo, Consolas, monospace;
}

.semibold {
font-weight: 500;
}

.form-mini {
display: flex;
gap: 10px;
max-width: 400px;
margin-bottom: 10px;

label {
display: none;
}

.form-group {
margin: 0;
flex: auto;
}
}

.subtle {
color: #999;

Expand Down
2 changes: 2 additions & 0 deletions ocfweb/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
<li><a href="{% url 'vhost_mail' %}">Mail Virtual Hosting</a></li>
{% endif %}

<li><a href="{% url 'account_info' %}">My Account</a></li>
<li><a href="{% url 'change_password' %}">Change Password</a></li>
<li><a href="{% url 'logout' %}?next={{request_full_path}}">Log Out</a></li>
</ul>
Expand Down Expand Up @@ -161,6 +162,7 @@ <h5>About the OCF</h5>
<h5>Account Tools</h5>
<ul class="list-unstyled">
<li><a href="{% url 'register' %}">Create Account</a></li>
<li><a href="{% url 'account_info' %}">My Account</a></li>
<li><a href="{% url 'change_password' %}">Reset Password</a></li>
<li><a href="{% url 'vhost_mail' %}">Mail Virtual Hosting</a></li>
</ul>
Expand Down