...
 
Commits (89)
......@@ -2,8 +2,11 @@
*.pyc
*~
srctweb/website/build/
.venv
.virtualevn
.venv
srctweb/_site/
.sass-cache/
.jekyll-metadata
.vs
.vscode
*.jekyll-cache
image: ruby:2.3
stages:
- build
- deploy
......@@ -7,32 +5,31 @@ stages:
variables:
JEKYLL_ENV: production
before_script:
- cd srctweb/
- bundle install
build:
image: ruby:2.3
stage: build
before_script:
- cd srctweb/
- bundle install
script:
- bundle exec jekyll build --trace -d '../build'
- cd srctweb/
- bundle install
- bundle exec jekyll build --trace -d '../build'
artifacts:
paths:
- build
- build
deploy_staging:
image: alpine
stage: deploy
script:
- echo 'Deploy bot awayyy';
- echo 'Deploy bot awayyy';
environment:
name: staging
url: https://srct.gmu.io
deploy_production:
image: alpine
stage: deploy
script: echo "Deploy bot awayyyyy"
script:
- echo "Deploy bot awayyyyy"
environment:
name: production
url: https://srct.gmu.edu
......
SRCTweb -- the homepage of Mason SRCT
SRCTweb -- the homepage of Mason SRCT.
Copyright (C) {{ site.time | date: '%y' }} Mason SRCT
This program is free software; you can redistribute it and/or
......
......@@ -35,7 +35,7 @@ use one at all), but Homebrew is highly reccomended.
To get homebrew, run the following command in a terminal:
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
**Note**: You do NOT need to use `sudo` when running any Homebrew commands, and
it likely won't work if you do.
......@@ -50,15 +50,7 @@ Finally we can install git with:
### On Windows
We recommend that if you are on Windows 10 AE (Anniversary Edition) or above to make use of the
Windows Subsystem for Linux (WSL). The following link should get you up and running:
[https://msdn.microsoft.com/en-us/commandline/wsl/install_guide](https://msdn.microsoft.com/en-us/commandline/wsl/install_guide)
#### Contributing with Windows
If you are not on Windows 10 or would rather prefer to not use the WSL you may download Git for
Windows here:
Download Git for Windows here:
[https://git-scm.com/download/win](https://git-scm.com/download/win)
......@@ -72,7 +64,7 @@ the SRCT code respository with SSH.
**a)** Configure your ssh keys by following the directions at:
**[git.gmu.edu/help/ssh/README](https://git.gmu.edu/help/ssh/README)**
**[https://git.gmu.edu/srct/schedules/wikis/Adding-SSH-Keys-to-GitLab](https://git.gmu.edu/srct/schedules/wikis/Adding-SSH-Keys-to-GitLab)**
**b)** Now, on your computer, navigate to the directory in which you want to download the project (ie. perhaps one called `~/development/SRCT`), and run
......@@ -91,7 +83,7 @@ and get to working on setting up a development environment!
Installing Docker on your system:
* For macOS go here: https://docs.docker.com/docker-for-mac/
* For Windows go here: https://docs.docker.com/docker-for-windows/
* For Windows (**PROFESSIONAL EDITION ONLY**) go here: https://docs.docker.com/docker-for-windows/
* For your specific linux disro go here: https://docs.docker.com/engine/installation/
* Additionally, you will need to install docker-compose: https://docs.docker.com/compose/install/
......@@ -105,6 +97,18 @@ If that doesn't work, try:
You should see that the server is running by going to [http://localhost:4000](http://localhost:4000) in your browser. Any changes you make to your local file system will be mirrored in the server.
### Installing Jekyll manually
#### Windows
1. Go to https://jekyllrb.com/docs/installation/windows/
2. Press the RubyInstaller link
3. Install the Ruby+Devkit 2.6.4-1 (x64)
4. Go through the installer
5. Open a terminal and type gem install jekyll bundler tzinfo tzinfo-data
6. Go to the folder you installed srctweb and type jekyll serve -s './srctweb' -d './srctweb/_site'
9. Navigate to localhost:4000 in a web browser
# Contrubuting
Please read `CONTRIBUTING.md` for specific information and best practices on how
......
......@@ -46,7 +46,7 @@ DEPENDENCIES
json
RUBY VERSION
ruby 2.4.1p111
ruby 2.5.1p57
BUNDLED WITH
1.15.3
1.16.1
......@@ -6,6 +6,9 @@ main:
- title: "Events"
url: "/events/"
- title: "News"
url: "/news/"
- title: "Calendar"
url: "/calendar/"
......
......@@ -2,6 +2,14 @@
{
"name": "David Haynes",
"email": "dhaynes3@gmu.edu",
"alum": true,
"exec": {
"status": false
}
},
{
"name": "Zac Wood",
"email": "zwood2@gmu.edu",
"alum": false,
"exec": {
"status": true,
......@@ -10,13 +18,21 @@
}
},
{
"name": "Zach Knox",
"email": "zknox@gmu.edu",
"name": "Gilberto Barrientos",
"email": "gbarrien@masonlive.gmu.edu",
"alum": false,
"exec": {
"status": true,
"position": "Vice President",
"link": "http://wiki.srct.gmu.edu/Vice_President"
"position": "Secretary",
"link": "http://wiki.srct.gmu.edu/Secretary"
}
},
{
"name": "Robert Hitt",
"email": "rhitt@gmu.edu",
"alum": false,
"exec": {
"status": false
}
},
{
......@@ -24,34 +40,28 @@
"email": "mbaile18@gmu.edu",
"alum": false,
"exec": {
"status": true,
"position": "Systems Administrator",
"link": "http://wiki.srct.gmu.edu/Systems_Administrator"
"status": false
}
},
{
"name": "Robert Hitt",
"email": "rhitt@gmu.edu",
"name": "Aaron Martinez",
"email": "apoulter@gmu.edu",
"alum": false,
"exec": {
"status": true,
"position": "Treasurer",
"link": "http://wiki.srct.gmu.edu/Treasurer"
"status": false
}
},
{
"name": "Danny Kim",
"email": "dkim74@gmu.edu",
"name": "Andres Villogas",
"email": "jvilloga@gmu.edu",
"alum": false,
"exec": {
"status": true,
"position": "Secretary",
"link": "http://wiki.srct.gmu.edu/Secretary"
"status": false
}
},
{
"name": "Kinga Dobolyi",
"email": "kdobolyi@gmu.edu",
"name": "Jonathan Bell",
"email": "bellj@gmu.edu",
"alum": false,
"exec": {
"status": true,
......@@ -59,6 +69,22 @@
"link": "http://wiki.srct.gmu.edu/Faculty_Advisor"
}
},
{
"name": "Zach Knox",
"email": "zknox@gmu.edu",
"alum": false,
"exec": {
"status": false
}
},
{
"name": "Danny Kim",
"email": "dkim74@gmu.edu",
"alum": false,
"exec": {
"status": false,
}
},
{
"name": "Bryon Bacon",
"email": "bbacon@gmu.edu",
......@@ -70,7 +96,7 @@
{
"name": "Jason Yeomans",
"email": "jyeoman2@gmu.edu",
"alum": false,
"alum": true,
"exec": {
"status": false
}
......@@ -120,7 +146,9 @@
"email": "ehasan3@gmu.edu",
"alum": false,
"exec": {
"status": false
"status": true,
"position": "Systems Administrator",
"link": "http://wiki.srct.gmu.edu/Systems_Administrator"
}
},
{
......@@ -166,7 +194,7 @@
{
"name": "Daniel Bond",
"email": "dbond2@gmu.edu",
"alum": false,
"alum": true,
"exec": {
"status": false
}
......@@ -211,14 +239,6 @@
"status": false
}
},
{
"name": "Andres Villogas",
"email": "jvilloga@gmu.edu",
"alum": false,
"exec": {
"status": false
}
},
{
"name": "Jay Wilson",
"email": "jwilso48@gmu.edu",
......@@ -240,7 +260,9 @@
"email": "ahrdy@gmu.edu",
"alum": false,
"exec": {
"status": false
"status": true,
"position": "Vice President",
"link": "http://wiki.srct.gmu.edu/Vice_President"
}
},
{
......@@ -408,39 +430,49 @@
"email": "rdecoito@gmu.edu",
"alum": false,
"exec": {
"status": false
"status": true,
"position": "Treasurer",
"link": "http://wiki.srct.gmu.edu/Treasurer"
}
},
{
"name": "Aaron Martinez",
"email": "apoulter@gmu.edu",
{
"name": "Molly Thomson",
"email": "mthomso2@gmu.edu",
"alum": false,
"exec": {
"status": false
}
},
{
"name": "Zac Wood",
"email": "zwood2@gmu.edu",
{
"name": "Ashlyn Gill",
"email": "agill15@gmu.edu",
"alum": false,
"exec": {
"status": false
}
},
{
"name": "Molly Thomson",
"email": "mthomso2@gmu.edu",
"name": "Christopher Gallarno",
"email": "cgallarn@gmu.edu",
"alum": false,
"exec": {
"status": false
}
},
{
"name": "Ashlyn Gill",
"email": "agill15@gmu.edu",
"alum": false,
"name": "Tyler Hallada",
"email": "thallada@gmu.edu",
"alum": true,
"exec": {
"status": false
}
},
{
"name": "Luke Faraone",
"email": "lfaraone@gmu.edu",
"alum": true,
"exec": {
"status": false
}
}
]
This diff is collapsed.
......@@ -3,7 +3,7 @@
<div class="row mt-2">
<div class="col-lg-12 text-center">
<a href="https://creativecommons.org/licenses/by-nc/4.0/legalcode">
<i class="fab fa-creative-commons fa-fw"></i> BY-NC 2016</a>
<i class="fab fa-creative-commons fa-fw"></i> BY-NC 2019</a>
Mason SRCT and <a href="https://git.gmu.edu/srct/srctweb/graphs/master">contributors</a>.
</div>
</div>
......
......@@ -11,7 +11,7 @@
<meta property="og:url" content="{{ site.url }}{{ page.permalink }}">
<meta property="og:type" content="website">
<meta property="og:title" content="{{ site.title }}{% if page.permalink != '/' %} | {{ page.title }}{% endif %}">
<meta property="og:image" content="{{ site.url }}/assets/img/SRCT_sq_white_shadow.png">
<meta property="og:image" content="{{ site.url }}/assets/img/SRCT_square_green_sm.png">
<meta property="og:description" content="{{ page.description }}">
<meta property="og:site_name" content="{{ site.title }}">
<meta property="og:locale" content="{{ site.locale }}">
......@@ -23,14 +23,27 @@
<meta name="twitter:url" content="{{ site.url }}{{ page.permalink }}">
<meta name="twitter:title" content="{{ site.title }}{% if page.permalink != '/' %} | {{ page.title }}{% endif %}">
<meta name="twitter:description" content="{{ page.description }}">
<meta name="twitter:image" content="{{ site.url }}/assets/img/SRCT_sq_white_shadow.png">
<meta name="twitter:image" content="{{ site.url }}/assets/img/SRCT_square_green_sm.png">
<!-- Load stylesheets -->
<link rel="stylesheet" href="https://srct.gmu.io/masonstrap/css/masonstrap.min.css" />
<link rel="stylesheet" href="https://srct.nyc3.digitaloceanspaces.com/masonstrap/masonstrap.min.css" />
<link href="/assets/css/style.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.pride.codes/css/bar_helpers.css">
<!-- Load favicon -->
<link rel="icon" href="/assets/img/favicon.ico">
{% if page.tablesorter_css %}
<link rel="stylesheet" href="/assets/css/theme.bootstrap_4.min.css">
{% endif %}
<link rel="icon" href="/assets/img/favicon.ico"> {% if page.tablesorter_css %}
<link rel="stylesheet" href="/assets/css/tablesorter.css"> {% endif %}
<!-- Matomo -->
<script type="text/javascript">
var _paq = _paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//matomo.srct.gmu.edu/";
_paq.push(['setTrackerUr1', u+'piwik.php']);
_paq.push(['setSiteId', '5']);
var d=document, g=d.createElement('script'), s=d.getElementsbyTagName('script')[0];
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<!-- End Matomo Code -->
\ No newline at end of file
......@@ -2,7 +2,7 @@
<div class="jumbotron jumbostyle">
<div class="container">
<div class="d-flex justify-content-center flex-wrap" id="srct-logo-home">
<div class="d-flex justify-content-center flex-wrap pt-3" id="srct-logo-home">
<img src="/assets/img/SRCT_sq_white_shadow.png" class="srct-logo" alt="SRCT's logo"/>
<p class="xolonium srct-title">Student-Run<br />Computing&nbsp;+<br />Technology</p>
</div>
......
......@@ -25,7 +25,7 @@
{% else %}
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" id="dropdown-link"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" href="#">
{{ link.title }}
</a>
<div class="dropdown-menu">
......@@ -39,4 +39,4 @@
</ul>
</div>
</div>
</nav>
\ No newline at end of file
</nav>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
<script src="/assets/js/functions.js"></script>
<script src="https://srct.nyc3.digitaloceanspaces.com/masonstrap/masonstrap.min.js"></script>
\ No newline at end of file
......@@ -8,6 +8,8 @@ layout: default
</h1>
{% if page.category == 'events' %}
<h4>{{ post.event_date | date: "%A %B %-d, %Y" }}</h4>
{% elsif post.author %}
<h4>by {{ post.author }} | {{ post.date | date: "%A %B %-d, %Y" }}</h4>
{% else %}
<h4>{{ post.date | date: "%A %B %-d, %Y" }}</h4>
{% endif %}
......@@ -17,23 +19,31 @@ layout: default
{% if post.hero_image %}
<div class="col-md-6">
<p>
<img class="img-fluid" src="{{ post.hero_image | absolute_url }}" alt={{ post.hero_alt }}>
<img class="img-fluid" src="{{ post.hero_image | prepend: site.url }}" alt={{ post.hero_alt }}>
</p>
</div>
<div class="col-md-6">
<p>
{{ post.excerpt }}
{% if post.content contains "<!-- more -->" %}
{{ post.content | split:"<!-- more -->" | first }}
{% else %}
{{ post.excerpt }}
{% endif %}
</p>
<p>
<a href="{{ post.url | absolute_url }}">Read More
<a href="{{ post.url | prepend: site.url }}">Read More
<i class="fas fa-arrow-circle-right"></i>
</a>
</p>
</div>
{% else %}
{{ post.excerpt }}
{% if post.content contains "<!-- more -->" %}
{{ post.content | split:"<!-- more -->" | first }}
{% else %}
{{ post.excerpt }}
{% endif %}
<p>
<a href="{{ post.url | absolute_url }}">Read More
<a href="{{ post.url | prepend: site.url }}">Read More
<i class="fas fa-arrow-circle-right"></i>
</a>
</p>
......@@ -44,5 +54,5 @@ layout: default
<br />
{% if page.archive %}
<p><a href="{{ page.archive | aosulute_url }}"><i class="fas fa-arrow-circle-left"></i> Archive</a></p>
<p><a href="{{ page.archive | prepend: site.url }}"><i class="fas fa-arrow-circle-left"></i> Archive</a></p>
{% endif %}
\ No newline at end of file
......@@ -20,6 +20,9 @@
<div class="container">
<div class="d-flex justify-content-center flex-wrap">
<h1 style="color: white">{{ page.title }}</h1>
{% if page.author %}
<h3 style="color: white">by {{ page.author }}</h1>
{% endif %}
</div>
</div>
</div>
......
......@@ -13,28 +13,9 @@ as well as some for more general discussion (such as #apple or #tv-film). Join a
<p>You can <strong><a href="https://srct.slack.com/signup">join our Slack team here</a></strong> with your Mason email address.</p>
<legend><i class="far fa-envelope fa-fw"></i>&nbsp;<strong>Mailing Lists</strong></legend>
<p>Please see <a href="http://lists.srct.gmu.edu/">this page</a> to sign up for mailing lists.</p>
<address>
<strong>Members and interested members of the community</strong><br>
srct-general@lists.srct.gmu.edu
</address>
<address>
<strong>Leadership team</strong><br>
exec@srct.gmu.edu
</address>
<address>
<strong>Developers</strong><br>
srct-devs@lists.srct.gmu.edu
</address>
<legend><i class="fas fa-users fa-fw"></i>&nbsp;<strong>Social Media</strong></legend>
<div class="row smidge">
<div class="row pb-2">
<div class="col-sm-4 centered">
<i class="fab fa-facebook fa-fw fa-lg"></i>&nbsp;&nbsp;<a href="https://facebook.com/MasonSRCT">facebook.com/MasonSRCT</a>
</div>
......@@ -46,7 +27,7 @@ srct-devs@lists.srct.gmu.edu
<a href="https://github.com/srct">github.com/srct</a>
</div>
</div>
<div class="row smidge">
<div class="row pb-2">
<div class="col-sm-4">
<i class="fab fa-trello fa-fw fa-lg"></i>&nbsp;&nbsp;<a href="https://trello.com/srct">trello.com/srct</a>
</div>
......
......@@ -61,6 +61,7 @@ Attempt to avoid unrelated topics that derail project channels. Small tangents a
5. Discuss politics in designated channels unless necessary or directly relevant.
6. Avoid usage of @everyone or @channel unless absolutely necessary, or if the channel is known to have many @channels.
7. Avoid repeatedly @ message (otherwise referred to as pinging) someone, especially if they’re unresponsive.
8. No soliciting.
</div>
<div class="col-sm-2 hidden-xs">
......
......@@ -190,11 +190,11 @@ permalink: /documents/logos/
<ul class="list-group list-group-flush">
<li class="list-group-item py-1">
<a href="/assets/media/SRCT_square_black_lg.png"
download="SRCT_square_black_lg.png">PNG (800x800)</a>
download="SRCT_square_white_lg.png">PNG (800x800)</a>
</li>
<li class="list-group-item py-1">
<a href="/assets/media/SRCT_square_black_sm.png"
download="SRCT_square_black_sm.png">PNG (400x400)</a></strong>
download="SRCT_square_white_sm.png">PNG (400x400)</a></strong>
</li>
</ul>
</div>
......
This diff is collapsed.
......@@ -7,29 +7,47 @@ tablesorter_css: true
<!-- Exec Table -->
<h3>
<strong><a href="http://wiki.srct.gmu.edu/Executive_Board">Executive Board</a></strong>
<strong>
<a href="http://wiki.srct.gmu.edu/Executive_Board">Executive Board</a>
</strong>
</h3>
<table class="table table-hover text-center">
<thead>
<tr>
<th></th>
<th><h4>Name</h4></th>
<th><h4>Position</h4></th>
<th><h4>Email</h4></th>
<th>
<h4>Name</h4>
</th>
<th>
<h4>Position</h4>
</th>
<th>
<h4>Email</h4>
</th>
</tr>
</thead>
<tbody>
{% for member in site.data.people %}
{% if member.exec.status == true %}
<tr>
<td><img class="exec-image" src="{{ member.email | get_gravatar }}" alt="gravatar image"></td>
<td class="align-middle"><h5>{{ member.name }}</h5></td>
<td class="align-middle"><h5><a href="{{ member.exec.link }}">{{ member.exec.position }}</a></h5></td>
<td class="align-middle"><h5><a href="mailto:{{ member.email }}">{{ member.email }}</a></h5></td>
</tr>
{% endif %}
{% endfor %}
{% for member in site.data.people %} {% if member.exec.status == true %}
<tr>
<td>
<img class="exec-image" src="{{ member.email | get_gravatar }}" alt="gravatar image">
</td>
<td class="align-middle">
<h5>{{ member.name }}</h5>
</td>
<td class="align-middle">
<h5>
<a href="{{ member.exec.link }}">{{ member.exec.position }}</a>
</h5>
</td>
<td class="align-middle">
<h5>
<a href="mailto:{{ member.email }}">{{ member.email }}</a>
</h5>
</td>
</tr>
{% endif %} {% endfor %}
</tbody>
</table>
......@@ -37,53 +55,70 @@ tablesorter_css: true
<div class="col-md-6">
<!-- Devs -->
<h3>
<strong><a href="http://wiki.srct.gmu.edu/Developers">Developers</a></strong>
<strong>
<a href="http://wiki.srct.gmu.edu/Developers">Developers</a>
</strong>
</h3>
<table id="devs-table" class="table table-hover text-center">
<thead>
<tr>
<th data-sorter="false"></th>
<th class="sorter-last-name"><h4>Name</h4></th>
<th data-sorter="false"><h4>Email</h4></th>
<th class="sorter-last-name">
<h4>Name</h4>
</th>
<th data-sorter="false">
<h4>Email</h4>
</th>
</tr>
</thead>
<tbody>
{% for member in site.data.people %}
{% if member.alum == false and member.exec.position != 'Faculty Advisor' %}
<tr>
<td><img class="member-image" src="{{ member.email | get_gravatar }}" alt="gravatar image"></td>
<td class="align-middle">{{ member.name }}</td>
<td class="align-middle"><a href="mailto:{{ member.email }}">{{ member.email }}</a></td>
</tr>
{% endif %}
{% endfor %}
{% for member in site.data.people %} {% if member.alum == false and member.exec.position
!= 'Faculty Advisor' %}
<tr>
<td>
<img class="member-image" src="{{ member.email | get_gravatar }}" alt="gravatar image">
</td>
<td class="align-middle">{{ member.name }}</td>
<td class="align-middle">
<a href="mailto:{{ member.email }}">{{ member.email }}</a>
</td>
</tr>
{% endif %} {% endfor %}
</tbody>
</table>
</div>
<div class="col-md-6">
<!-- Alum -->
<h3>
<strong><a href="#">Alumni</a></strong>
<strong>
<a href="#">Alumni</a>
</strong>
</h3>
<table id="alums-table" class="table table-hover text-center">
<thead>
<tr>
<th data-sorter="false"></th>
<th class="sorter-last-name"><h4>Name</h4></th>
<th data-sorter="false"><h4>Email</h4></th>
<th class="sorter-last-name">
<h4>Name</h4>
</th>
<th data-sorter="false">
<h4>Email</h4>
</th>
</tr>
</thead>
<tbody>
{% for member in site.data.people %}
{% if member.alum == true %}
<tr>
<td><img class="member-image" src="{{ member.email | get_gravatar }}" alt="gravatar image"></td>
<td class="align-middle">{{ member.name }}</td>
<td class="align-middle"><a href="mailto:{{ member.email }}">{{ member.email }}</a></td>
</tr>
{% endif %}
{% endfor %}
{% for member in site.data.people %} {% if member.alum == true %}
<tr>
<td>
<img class="member-image" src="{{ member.email | get_gravatar }}" alt="gravatar image">
</td>
<td class="align-middle">{{ member.name }}</td>
<td class="align-middle">
<a href="mailto:{{ member.email }}">{{ member.email }}</a>
</td>
</tr>
{% endif %} {% endfor %}
</tbody>
</table>
</div>
......@@ -91,31 +126,35 @@ tablesorter_css: true
<script src="/assets/js/jquery.tablesorter.min.js" type="text/javascript"></script>
<script>
$(function() {
// from https://stackoverflow.com/questions/38209618/
// response there by the person who maintains the project
$.tablesorter.addParser({
id: 'last-name',
is: function() {
return false;
},
format: function(str) {
var parts = (str || '').split(/\s+/),
last = parts.pop();
parts.unshift(last);
return parts.join(' ');
},
// set type, either numeric or text
type: 'text'
});
$(function () {
// from https://stackoverflow.com/questions/38209618/
// response there by the person who maintains the project
$.tablesorter.addParser({
id: 'last-name',
is: function () {
return false;
},
format: function (str) {
var parts = (str || '').split(/\s+/),
last = parts.pop();
parts.unshift(last);
return parts.join(' ');
},
// set type, either numeric or text
type: 'text'
});
$("#devs-table").tablesorter({
theme: "bootstrap",
sortList: [[1,0]]
});
$("#alums-table").tablesorter({
theme: "bootstrap",
sortList: [[1,0]]
$("#devs-table").tablesorter({
theme: "bootstrap",
sortList: [
[1, 0]
]
});
$("#alums-table").tablesorter({
theme: "bootstrap",
sortList: [
[1, 0]
]
});
});
});
</script>
......@@ -11,11 +11,13 @@ description: "Projects created and maintained by SRCT's members."
<div class="row">
{% for project in site.data.projects %}
{% if project.status == 'active' %}
<div class="col-lg-6 project-entry">
<div class="col-lg-6 mb-2">
<a class="project-link" name="{{ project.name }}" href="#{{ project.name }}"><i class="{{ project.fa_icon }} project-icon"></i></a>
<legend>
<strong>{{ project.name }}</strong>
{% if project.deployed_url %}| <a href="https://{{ project.deployed_url }}">{{ project.deployed_url }}</a>{% endif %}
{% if project.deployed_url %}| <a href="https://{{ project.deployed_url }}" target="_blank">{{ project.deployed_url }}</a>{% endif %}
{% if project.appstore_url %}<br /><a href="{{ project.appstore_url }}" target="_blank"><img class="store-badge" src="/assets/img/AppStoreBadge.png" alt="Download on the App Store"></a>{% endif %}
{% if project.googleplay_url %}<br /><a href="{{ project.googleplay_url }}" target="_blank"><img class="store-badge" src="/assets/img/GooglePlayBadge.png" alt="Get It on Google Play"></a>{% endif %}
</legend>
{% if project.docs_url %}<a href="{{ project.docs_url }}">Docs</a>{% endif %}
{% if project.issues_url %}| <a href="{{ project.issues_url }}">Issues</a><br><br>{% endif %}
......@@ -26,7 +28,7 @@ description: "Projects created and maintained by SRCT's members."
{% if project.next_release %}<strong class="project-role">Next Release:</strong> <a href="{{ project.next_release_url }}">{{ project.next_release }}</a><br>{% endif %}
{% if project.language %}<strong class="project-role">Language:</strong> {{ project.language }}{% endif %}
<p class="project-text">
<p class="mt-2 pb-3">
{{ project.blurb }}
</p>
</div>
......@@ -41,11 +43,11 @@ description: "Projects created and maintained by SRCT's members."
<div class="row">
{% for project in site.data.projects %}
{% if project.status == 'in_dev' %}
<div class="col-lg-6 project-entry">
<div class="col-lg-6 mb-2">
<a class="project-link" name="{{ project.name }}" href="#{{ project.name }}"><i class="{{ project.fa_icon }} project-icon"></i></a>
<legend>
<strong>{{ project.name }}</strong>
{% if project.deployed_url %}| <a href="https://{{ project.deployed_url }}">{{ project.deployed_url }}</a>{% endif %}
{% if project.deployed_url %}| <a href="https://{{ project.deployed_url }}" target="_blank">{{ project.deployed_url }}</a>{% endif %}
</legend>
{% if project.docs_url %}<a href="{{ project.docs_url }}">Docs</a>{% endif %}
{% if project.issues_url %}| <a href="{{ project.issues_url }}">Issues</a>{% endif %}
......@@ -57,7 +59,7 @@ description: "Projects created and maintained by SRCT's members."
{% if project.next_release %}<strong class="project-role">Next Release:</strong> <a href="{{ project.next_release_url }}">{{ project.next_release }}</a><br>{% endif %}
{% if project.language %}<strong class="project-role">Language:</strong> {{ project.language }}{% endif %}
<p class="project-text">
<p class="mt-2 pb-3">
{{ project.blurb }}
</p>
</div>
......@@ -72,11 +74,11 @@ description: "Projects created and maintained by SRCT's members."
<div class="row">
{% for project in site.data.projects %}
{% if project.status == 'inactive' %}
<div class="col-lg-6 project-entry">
<div class="col-lg-6 mb-2">
<a class="project-link" name="{{ project.name }}" href="#{{ project.name }}"><i class="{{ project.fa_icon }} project-icon"></i></a>
<legend>
<strong>{{ project.name }}</strong>
{% if project.deployed_url %}| <a href="https://{{ project.deployed_url }}">{{ project.deployed_url }}</a>{% endif %}
{% if project.deployed_url %}| <a href="https://{{ project.deployed_url }}" target="_blank">{{ project.deployed_url }}</a>{% endif %}
</legend>
{% if project.docs_url %}<a href="{{ project.docs_url }}">Docs</a>{% endif %}
{% if project.issues_url %}| <a href="{{ project.issues_url }}">Issues</a>{% endif %}
......@@ -88,7 +90,7 @@ description: "Projects created and maintained by SRCT's members."
{% if project.next_release %}<strong class="project-role">Next Release:</strong> <a href="{{ project.next_release_url }}">{{ project.next_release }}</a><br>{% endif %}
{% if project.language %}<strong class="project-role">Language:</strong> {{ project.language }}{% endif %}
<p class="project-text">
<p class="mt-2 pb-3">
{{ project.blurb }}
</p>
</div>
......@@ -103,11 +105,11 @@ description: "Projects created and maintained by SRCT's members."
<div class="row">
{% for project in site.data.projects %}
{% if project.status == 'ideas' %}
<div class="col-lg-6 project-entry">
<div class="col-lg-6 mb-2">
<a class="project-link" name="{{ project.name }}" href="#{{ project.name }}"><i class="{{ project.fa_icon }} project-icon"></i></a>
<legend>
<strong>{{ project.name }}</strong>
{% if project.deployed_url %}| <a href="https://{{ project.deployed_url }}">{{ project.deployed_url }}</a>{% endif %}
{% if project.deployed_url %}| <a href="https://{{ project.deployed_url }}" target="_blank">{{ project.deployed_url }}</a>{% endif %}
</legend>
{% if project.docs_url %}<a href="{{ project.docs_url }}">Docs</a>{% endif %}
{% if project.issues_url %}| <a href="{{ project.issues_url }}">Issues</a>{% endif %}
......@@ -119,7 +121,7 @@ description: "Projects created and maintained by SRCT's members."
{% if project.next_release %}<strong class="project-role">Next Release:</strong> <a href="{{ project.next_release_url }}">{{ project.next_release }}</a><br>{% endif %}
{% if project.language %}<strong class="project-role">Language:</strong> {{ project.language }}{% endif %}
<p class="project-text">
<p class="mt-2 pb-3">
{{ project.blurb }}
</p>
</div>
......
---
title: "Tales of IMT #1: Addressing Aquia and How SRCT Content Gets Served"
layout: post
categories: news
slug: imt-ep-1
date: 2018-04-29T00:00:00-0400
hero_image: "/assets/img/servers.jpg"
hero_alt: "Future Aquia Servers in a car"
author: "Michael Bailey"
---
This is going to be one part of what will presumably be part of a multi-piece transparency initiative in which I, Michael Bailey (Lead Systems Admin on the Infrastructure Management Team at SRCT), show the campus community (and SRCT) how information is served at SRCT. I'll cover how our sites are served and a few IT tricks we use including Host matching, reverse proxy, and auditing. **These pieces are going to tow a line between what is right and what we do**. I will try to disclaim what we do and what the right move would be to do, because they aren't always the same as this is effectively a volunteer position with limited resources.
<!--more-->
# Addressing Aquia
I've been hearing a lot in terms of people wondering what the situation is with Aquia. Presently we are working on having relatively semantic changes shuffled between us and Professor Bell according to ITS's requests and concerns. We are working now on getting our servers to a new intermediate location until we can move in. After all of this is done, we may need to hold for background checks. They have not started to my knowledge and really only apply to me.
# How Requests are Made to Us
Essentially, whenever a browser is provided a URL like go.gmu.edu, it asks a series of servers where it actually is on the internet via it's [IP Address](https://en.wikipedia.org/wiki/IP_address). This is a configuration known as [DNS](https://en.wikipedia.org/wiki/Domain_Name_System) and we have ours configured at [Hurricane Electric](http://www.he.net/). Our *.gmu.edu domains were handled with an agreement with [GMU Networking](https://itservices.gmu.edu/services/view-service.cfm?customel_dataPageID_4609=6141). As a reminder or if you weren't aware, pretty much everyone on the Infrastructure Management Team is in the workforce, so there's some vested trust in how we handle things.
![imt](/assets/img/imt/dns.png "dhaynes making dns requests")
# What Happens After Requests Are Made To Us
So now we have a web request we need to fulfill sent to 107.170.176.214. All we have to go on as far as fulfilling their request is the browser requesting from our IP right? **This is a key misconception.** We get a wide variety of information, including, on average, what is below. Not only can we use this information to route your request to the right site internally, we can use this to handle other things, such as if we are able to serve you an old copy without issue ([caching](https://en.wikipedia.org/wiki/Cache_(computing))).
![imt](/assets/img/imt/go_request.png "HTTP Payload ")
As an example of caching, services like Whats Open can cache data in certain cases. For instance, if you requested what was open at 3:00pm, while the interface may change as far as what is closed when you ask again at 3:05pm, the actual hours aren't changed so we are free and clear to serve you "stale" hours without requiring the server to go back and fetch the hours again, which may take processing power.
More importantly, routing the request properly. A key element our web server, nginx, is able to manage is the "Host" header. It can read this and determine what actual page you're trying to visit. It's a simple configuration in nginx called [server_name](http://nginx.org/en/docs/http/server_names.html). It defines what configurations should be taken into effect in what cases.
# Redirecting Request Internally
Despite being rich applications in most cases rather than just static HTML, we host multiple applications of multiple types on our servers.
Take for instance "albert", where following web configurations/routes exist.
```
albert bookshare gitbot icinga-web.conf
pgp pmwiki roomlist schedules weather
api default go mediawiki
piwik punycode sched-joke srctweb
whats-open-web
```
As a result, we really squeeze resources out. We have 2GB of memory on albert, leaverage swap, and 30GB of disk on Albert. Gitlab is on a much bigger dedicated box, so that's a different story.
But what does this actual delivery look like? Take for instance our Go example.
Here's ashortened version of what's in production, ignoring certain overrided paths, comments or anything "extra" we don't need to care about.
```
server {
listen 443 ssl;
include ssl.conf;
server_name go.gmu.edu;
ssl_certificate /etc/nginx/ssl/go/go-chain.crt;
ssl_certificate_key /etc/nginx/ssl/go/go.key;
location / {
proxy_pass http://localhost:9992/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 10s;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
error_page 502 /502.html;
error_page 504 /502.html;
}
```
This is effectively what configures go. So what does this actually do? Let's break them down.
`listen 443 ssl` enables HTTPS on HTTPS's port (443), that pretty HTTPS lock you see in your browser. This is supported by `ssl_certificate` and `ssl_certificate_key`. There's another configuration to reroute HTTP (plaintext) requests to HTTPS (secure) for the user experience.
`server_name` is effectively what we discussed in the past where we check the Host header. [For more, see Nginx's documentation on it](http://nginx.org/en/docs/http/request_processing.html).
`proxy_pass` is the key part. It tells the browser any requests under the path (`/` being virtually every request) to port 9992 on the server. This lets us host multiple sites and services, whether they're Django apps or other apps, often in Docker containers, at the same time on a series of innocuous ports and keep them out of sight and out of mind.
Other settings ensure even in the internal service sitting on port 9992 we are still getting key info like the Host. Django cares about this, because if you visit `terroristbombs.veryunsafe.com` or the raw IP of the server (in our case wouldn't work) and it's pointed at Go, Go may not want to serve you it.
All of this proxying is why if you visit the [raw IP of any of our servers](http://107.170.176.214/) you either get nothing useful or a failure of some variety.
# Once It Reaches The Right Port
We now need to check out what service is on port 9992 to actually manage anything granular about go. We run `lsof -i -n -P|grep 9992` as root to list useful information about ports to commands and search for 9992 specifically.
We get
```
systemd 1 root 107u IPv4 30604 0t0 TCP 127.0.0.1:9992 (LISTEN)
gunicorn 1265 go 7u IPv4 30604 0t0 TCP 127.0.0.1:9992 (LISTEN)
gunicorn 23126 go 7u IPv4 30604 0t0 TCP 127.0.0.1:9992 (LISTEN)
```
First and foremost, `systemd` is a fundamental building block system for Linux but probably indicates it has a `systemctl` service set for the application. In Go's case, this is set up.
```
root@albert:/etc/nginx/sites-enabled# systemctl status go
● go.service - Roomlist Gunicorn daemon
Loaded: loaded (/etc/systemd/system/go.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2018-04-11 16:32:18 EDT; 2 weeks 4 days ago
Main PID: 1265 (gunicorn)
Tasks: 2
Memory: 45.8M
CPU: 9min 15.871s
CGroup: /system.slice/go.service
├─ 1265 /srv/go/venv/bin/python2 /srv/go/venv/bin/gunicorn --pid /run/go/pid --log-level=debug --timeout=20 -b 127.0.0.1:9992
└─23126 /srv/go/venv/bin/python2 /srv/go/venv/bin/gunicorn --pid /run/go/pid --log-level=debug --timeout=20 -b 127.0.0.1:9992
Apr 30 09:13:41 albert.srct.gmu.edu gunicorn[1265]: [2018-04-30 09:13:41 +0000] [23126] [DEBUG] GET /
Apr 30 09:18:41 albert.srct.gmu.edu gunicorn[1265]: [2018-04-30 09:18:41 +0000] [23126] [DEBUG] GET /
Apr 30 09:23:41 albert.srct.gmu.edu gunicorn[1265]: [2018-04-30 09:23:41 +0000] [23126] [DEBUG] GET /
Apr 30 09:28:41 albert.srct.gmu.edu gunicorn[1265]: [2018-04-30 09:28:41 +0000] [23126] [DEBUG] GET /
```
We won't go in depth as to how the service is configured, but I should disclose in production it technically says `9991` in the command lines under "CGroup" but in almost all services it'd say `9992` in the command lines and it's functionally the same.
**It's worth noting another (probably better) way to do all of this is through UNIX Sockets** or in Django's case uwsgi. For more on Sockets, see the Tweeted comic below by Julia Evans aka @b0rk.
[![imt](/assets/img/imt/sockets.png "Sockets comic")](https://twitter.com/b0rk/status/810261842291462145)
So now we have a request that goes from the browser, to our server, to an internal port, and back out to the interwebz! Could be better, could be worse, but given limited man-hours and infrastructure, this is how most SRCT services look.
<style>
img[alt="imt"] {
width: 25%;
}
@media only screen and (max-width: 600px) {
img[alt="imt"] {
width: 100%;
}
}
</style>
\ No newline at end of file
/* Sticky footer styles */
html {
position: relative;
min-height: 100%;
}
body {
/* Margin bottom by footer height */
margin-bottom: 120px;
}
.footer {
position: absolute;
bottom: 0;
......@@ -17,29 +20,33 @@ body {
}
/* Custom page CSS */
a[name] {
padding-top: 50px;
}
@font-face {
font-family: 'Xolonium';
src: url('../fonts/Xolonium-Regular.otf') format("opentype");
font-family: 'Xolonium';
src: url('../fonts/Xolonium-Regular.otf') format("opentype");
}
.xolonium {
font-family: Xolonium;
}
#srct-logo-home {
padding-top: 1rem;
}
.srct-logo {
height: 10rem;
width: 10rem;
width: 10rem;
}
.srct-title {
color: white;
font-size: 2rem;
padding-top: 0.35rem;
padding-left: 0.5rem;
text-shadow: 1px 1px 6px #333;}
text-shadow: 1px 1px 6px #333;
}
.jumbostyle {
background: url(/assets/img/meeting.jpg) no-repeat;
background-size: cover;
......@@ -49,35 +56,10 @@ a[name] {
padding-bottom: 100px;
border-radius: unset;
}
.srctlogo {
width: 10px;
}
.smidge {
padding-bottom: 10px;
}
.smidgen {
padding-bottom: 5px;
}
.people-left {
padding-left:0;
padding-right:0;
}
.people-right {
padding-right:0;
padding-left:0;
}
@media(min-width:992px){
.people-left {
padding-right:15px;
}
.people-right {
padding-left:15px;
}
}
.index-card {
margin-bottom: 1rem;
}
.index-image {
border-radius: 50%;
......@@ -99,47 +81,54 @@ a[name] {
* A cool little hack I found to try to allow a responsive Google Cal:
* http://themeloom.com/2013/02/tips-embed-google-maps-and-calendars-in-a-responsive-wordpress-theme/
**/
.googlecal-container {
position: relative;
padding-bottom: 56.25%;
padding-top: 30px;
height: 0;
overflow: hidden;
position: relative;
padding-bottom: 56.25%;
padding-top: 30px;
height: 0;
overflow: hidden;
}
.googlecal-container iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
/** Projects Page **/
.project-entry {
margin-bottom:10px;
}
.project-icon {
text-align:center;
text-align: center;
display: block;
font-size:100px;
margin:0 auto;
font-size: 100px;
margin: 0 auto;
padding-bottom: 10px;
}
/* can't you extend CSS classes? */
.project-link {
/* Padding and margin business because of the static header */
padding-top:50px !important;
margin-top:-50px;
display:block;
color:#000;
padding-top: 50px !important;
margin-top: -50px;
display: block;
color: #000;
}
.project-link:hover, .project-link:active, .project-link:focus {
.project-link:hover,
.project-link:active,
.project-link:focus {
text-decoration: none;
outline: 0;
}
.project-icon-stacked {
font-size:55px;
font-size: 55px;
}
.project-role {
width: 150px;
display: inline-block;
......@@ -150,30 +139,35 @@ a[name] {
background: transparent;
font-size: 0.9em;
}
.project-text {
margin-top:10px;
padding-bottom:15px;
}
#banner {
padding-top: 5rem;
padding-top: 2rem;
background: #e4e6d7;
width: 100%;
margin-bottom: 15px;
font-size: 22.5px;
}
.page-header {
margin-top:0;
border-bottom:none;
margin-top: 0;
border-bottom: none;
}
.white-branding {
color: black;
background-color: white;
}
.green-branding {
color: white;
background-color: #006633;
}
.black-branding {
color: white;
background-color: black;
}
\ No newline at end of file
}
.store-badge {
padding: 2px;
}
.tablesorter-bootstrap {
width: 100%
}
.tablesorter-bootstrap tfoot td,
.tablesorter-bootstrap tfoot th,
.tablesorter-bootstrap thead td,
.tablesorter-bootstrap thead th {
font: 14px/20px Arial, Sans-serif;
font-weight: 700;
padding: 4px;
margin: 0 0 18px
}
.tablesorter-bootstrap thead .tablesorter-header {
background-position: right 5px center;
background-repeat: no-repeat;
cursor: pointer;
white-space: normal
}
.tablesorter-bootstrap:not(.table-dark) tfoot td,
.tablesorter-bootstrap:not(.table-dark) tfoot th,
.tablesorter-bootstrap:not(.table-dark) thead:not(.thead-dark) .tablesorter-header {
background-color: #fff
}
.tablesorter-bootstrap thead .sorter-false {
cursor: default;
background-image: none