Compare commits

..

13 Commits

Author SHA1 Message Date
122faaae85
.
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-30 23:51:30 +01:00
0263964326
.
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-30 23:45:38 +01:00
121cc23cdf
.
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-30 23:41:13 +01:00
55c3793c0e
.
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-30 23:33:35 +01:00
66e603324d
.
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-30 23:29:12 +01:00
6c49ca08bf
.
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-30 22:57:41 +01:00
9ba879666c
.
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-30 22:55:29 +01:00
e793bb288d
.
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-30 22:51:16 +01:00
42cc8e43e1
.
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-30 22:44:54 +01:00
f7f8ba936c
.
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-30 22:43:03 +01:00
a9c8cb7dbd
.
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-30 22:40:23 +01:00
37221989f6
.
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-30 22:29:49 +01:00
2e7595d639
.
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-30 22:22:40 +01:00
21 changed files with 195 additions and 577 deletions

8
.drone.yml Normal file
View File

@ -0,0 +1,8 @@
kind: pipeline
name: default
steps:
- name: build
image: golang
commands:
- make build

4
.gitignore vendored
View File

@ -11,11 +11,7 @@ dist/
# CDN link
cdn/
cdn
cdn_/
cdn_
# Config Link
cnf/
cnf
cnf_/
cnf_

8
.idea/misc.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="SwUserDefinedSpecifications">
<option name="specTypeByUrl">
<map />
</option>
</component>
</project>

View File

@ -1,12 +0,0 @@
platform: linux/amd64
pipeline:
format:
image: golang
commands:
- files=$(gofmt -l .) && echo "$files" && [ -z "$files" ]
build:
image: golang
commands:
- make build

View File

@ -1,7 +1,6 @@
SHELL := /bin/bash
PRODUCT_NAME := wappcityuni
BIN := dist/${PRODUCT_NAME}
DNAME := ${PRODUCT_NAME}_
ENTRY_POINT := ./cmd/${PRODUCT_NAME}
HASH := $(shell git rev-parse --short HEAD)
COMMIT_DATE := $(shell git show -s --format=%ci ${HASH})
@ -12,10 +11,9 @@ COMP_BIN := go
ifeq ($(OS),Windows_NT)
BIN := $(BIN).exe
DNAME := $(DNAME).exe
endif
.PHONY: build dev test clean deploy d
.PHONY: build dev test clean deploy
build:
mkdir -p dist/
@ -41,12 +39,3 @@ deploy: build
sudo cp *.css cdn
sudo cp *.js cdn
sudo systemctl start wappcityuni
d: build
sudo systemctl stop wappcityuni_
sudo cp "${BIN}" "/usr/local/bin/${DNAME}"
sudo cp *.go.html cnf_
sudo cp *.go.yml cnf_
sudo cp *.css cdn_
sudo cp *.js cdn_
sudo systemctl start wappcityuni_

View File

@ -1,13 +1,13 @@
# Captain ALM Cityuni subdomain WebServer
[![Build Status](https://ci.mrmelon54.com/api/badges/alfred/cityuni-webserver/status.svg)](https://ci.mrmelon54.com/alfred/cityuni-webserver)
[![Build Status](https://ci.mrmelon54.xyz/api/badges/alfred/cityuni-webserver/status.svg)](https://ci.mrmelon54.xyz/alfred/cityuni-webserver)
This provides my template and cache supporting web / application server for my city university portfolio subdomain.
[Production Server](https://cityuni.captainalm.com/)
Maintainer:
[Captain ALM](https://code.mrmelon54.com/alfred)
[Captain ALM](https://code.mrmelon54.xyz/alfred)
License:
[BSD 3-Clause](https://code.mrmelon54.com/alfred/cityuni-webserver/src/branch/master/LICENSE)
[BSD 3-Clause](https://code.mrmelon54.xyz/alfred/GOPackageHeaderServer/src/branch/master/LICENSE)

View File

@ -6,18 +6,8 @@ Under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 Internati
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Times New Roman", Times, serif;
}
#st{
position: absolute;
left: -1080px;
top: -1080px;
font-size: 1em;
visibility: hidden;
white-space: nowrap;
}
main{
display: block;
padding-top: 70px;
padding-left: 6px;
}
@ -50,7 +40,7 @@ main{
.home-button, .sort-button{
display: inline-block;
width: 84px;
height: 66px;
height: 62px;
overflow: hidden;
text-align: center;
}
@ -69,15 +59,6 @@ main{
overflow: hidden;
max-height: 0;
}
.vnav{
max-height: none;
top: 0;
position: relative;
float: right;
width: auto;
height: 100%;
overflow: hidden;
}
.so-pane{
display: none;
overflow: hidden;
@ -131,24 +112,15 @@ main{
.nav-menu, .sort-menu{
display: none;
}
.menu a, .vmenu a{
.menu a{
display: block;
}
.menu a, .vmenu a, #st{
padding: 24px 16px;
font-weight: bold;
}
.vmenu li{
float: left;
}
.vmenu a:hover{
background-color: transparent;
padding: 22px 18px;
}
.hmb{
cursor: pointer;
float: right;
background-color: transparent;
padding: 32px 20px;
padding: 30px 20px;
}
.hmb-line{
display: block;
@ -170,7 +142,7 @@ main{
.hmb-line::after{
top: -5px;
}
.nav-menu:checked ~ #nav, .nav-open{
.nav-menu:checked ~ nav, .nav-open{
max-height: 100%;
}
.nav-menu:checked ~ .hmb .hmb-line, .nav-open-hmb .hmb-line{
@ -190,8 +162,8 @@ main{
box-sizing: content-box;
position: fixed;
text-align: center;
top: 70px;
left: 20px;
top: 66px;
left: 18px;
max-height: 100%;
width: 230px;
height: auto;
@ -210,7 +182,7 @@ main{
display: table;
box-sizing: inherit;
}
.main-box > div, footer{
.main-box > div, footer > p{
max-width: 100%;
margin: 3px 0;
padding: 2px;
@ -274,7 +246,7 @@ main{
overflow: hidden;
}
.item-table > div > div > div{
padding: 4px;
padding: 2px;
}
.item-table-caption, .so-pane-caption{
display: table-caption !important;
@ -302,11 +274,11 @@ main{
border-width: 1px;
margin: 2px;
}
@media (min-width: 600px){
@media (min-width: 560px){
.main-box > div{
padding: 12px;
}
footer{
footer > p{
padding: 4px;
}
.item-table > div{
@ -327,7 +299,7 @@ main{
margin: 10px;
}
}
@media (min-width: 680px){
@media (min-width: 640px){
.nav{
max-height: none;
top: 0;
@ -335,9 +307,6 @@ main{
float: right;
width: auto;
}
.vnav{
display: none;
}
.menu li{
float: left;
}
@ -355,4 +324,4 @@ main{
.item-table-caption{
display: block !important;
}
}
}

View File

@ -1,19 +0,0 @@
package conf
import "strings"
type PageYaml struct {
PageName string `yaml:"pageName"`
PagePath string `yaml:"pagePath"`
}
func (py PageYaml) GetPagePath() string {
toReturn := py.PagePath
if !strings.HasSuffix(toReturn, ".go") {
toReturn += ".go"
}
if !strings.HasPrefix(toReturn, "/") {
toReturn = "/" + toReturn
}
return toReturn
}

View File

@ -9,13 +9,10 @@ import (
type ServeYaml struct {
DataStorage string `yaml:"dataStorage"`
TemplateStorage string `yaml:"templateStorage"`
Domains []string `yaml:"domains"`
RangeSupported bool `yaml:"rangeSupported"`
EnableGoInfoPage bool `yaml:"enableGoInfoPage"`
CacheSettings CacheSettingsYaml `yaml:"cacheSettings"`
PageSettings []PageYaml `yaml:"pageSettings"`
YmlDataFallback bool `yaml:"ymlDataFallback"`
}
func (sy ServeYaml) GetDomainString() string {
@ -42,20 +39,3 @@ func (sy ServeYaml) GetDataStoragePath() string {
return sy.DataStorage
}
}
func (sy ServeYaml) GetTemplateStoragePath() string {
if sy.TemplateStorage == "" || !filepath.IsAbs(sy.TemplateStorage) {
wd, err := os.Getwd()
if err != nil {
return ""
} else {
if sy.TemplateStorage == "" {
return wd
} else {
return path.Join(wd, sy.TemplateStorage)
}
}
} else {
return sy.TemplateStorage
}
}

View File

@ -4,13 +4,9 @@ listen:
webMethod: "http"
identify: true
serve:
dataStorage: ""
domains: []
rangeSupported: true
enableGoInfoPage: true
cacheSettings:
enableTemplateCaching: false
enableTemplateCachePurge: false
enableContentsCaching: true
enableContentsCachePurge: true
maxAge: 3600

View File

@ -10,13 +10,13 @@ body{
a{
color: #b0b0f0;
}
.header, nav, footer, .so-pane{
.header, .nav, footer, .so-pane{
background-color: #1d1d1e;
}
.home-button > div, .sort-button > div, .menu a, .vmenu a, .so-pane > form > div > * > *{
.home-button > div, .sort-button > div, .menu a, .so-pane > form > div > * > *{
color: #e0e0e0;
}
.home-button:hover, .menu a:hover, .vmenu a:hover, .hmb:hover, .sort-button:hover, .sort-menu:checked ~ .sort-button, .sort-button-active, .so-pane > form > div > span > input, .so-pane > form > div > div > select{
.home-button:hover, .menu a:hover, .hmb:hover, .sort-button:hover, .sort-menu:checked ~ .sort-button, .sort-button-active, .so-pane > form > div > span > input, .so-pane > form > div > div > select{
background-color: #606061;
}
.hmb-line, .hmb-line::before, .hmb-line::after{

View File

@ -67,10 +67,6 @@
<tr>
<th>Product Description</th>
<td>{{ .ProductDescription }}</td>
</tr>
<tr>
<th>Product License</th>
<td>BSD 3-Clause License</td>
</tr>
<tr>
<th>Product Location</th>
@ -150,10 +146,6 @@
<th>Memory Page Size</th>
<td>{{ .PageSize }}</td>
</tr>
<tr>
<th>System Time</th>
<td>{{ .CurrentTime }}</td>
</tr>
</table>
</p>
<p>

View File

@ -5,7 +5,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta name="description" content="Captain ALM's City University Portfolio">
<meta name="keywords" content="CaptainALM Captain_ALM Captain ALM portfolio Alfred Manville projects programming hacking cracking city uni cityuni cuol City University of London mycityuni">
<meta name="keywords" content="CaptainALM Captain_ALM Captain ALM portfolio Alfred Manville projects programming hacking cracking">
<title>City University Portfolio</title>
<link rel="stylesheet" href="{{ .Data.CSSBaseURL }}"/>
{{ if .Light }}
@ -95,14 +95,10 @@
</div>
<input class="nav-menu" type="checkbox" id="nav-menu"/>
<label class="hmb" for="nav-menu" title="Navigation Links"><span class="hmb-line"></span></label>
<nav class="vnav" id="vnav">
<ul class="vmenu no-lst-style" id="vmenu">
</ul>
</nav>
<nav class="nav" id="nav">
<ul class="menu no-lst-style" id="menu">
<ul class="menu no-lst-style">
{{ range .Data.GetHeaderLabels }}
<li><a href="{{ $.Data.GetHeaderLink . }}" class="no-dec" title="{{ . }}">{{ . }}</a></li>
<li><b><a href="{{ $.Data.GetHeaderLink . }}" class="no-dec" title="{{ . }}">{{ . }}</a></b></li>
{{ end }}
</ul>
</nav>
@ -155,15 +151,10 @@
<div class="item-table-360">
<div id="video-{{ $c }}">
{{ if eq .VideoLocation "" }}
<img src="{{ .GetVideoThumbnail $.Data.NoVideoImageLocation }}" alt="No Video" width="360px">
<img src="{{ $.Data.NoVideoImageLocation }}" alt="No Video" width="360px">
{{ else }}
{{ if .IsVideoLink }}
<a href="{{ .VideoLocation }}">
<img src="{{ .GetVideoThumbnail $.Data.PlayVideoImageLocation }}" alt="Play Video" title="Play" width="360px">
</a>
{{ else }}
<script type="application/javascript">
CreateVideoPlaceholder({{ $c }}, "{{ .GetVideoThumbnail $.Data.PlayVideoImageLocation }}")
CreateVideoPlaceholder({{ $c }})
</script>
<noscript>
<video controls width="360px">
@ -171,7 +162,6 @@
<a href="{{ .VideoLocation }}">The Video</a>
</video>
</noscript>
{{ end }}
{{ end }}
</div>
</div>
@ -196,11 +186,6 @@
<p>
Looking for the old static HTML page, here's the <a href="index.html">link</a>.
</p>
<p>
This page's content is licensed under Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International <a href="https://creativecommons.org/licenses/by-nc-nd/4.0/">
<img src="https://mirrors.creativecommons.org/presskit/buttons/80x15/png/by-nc-nd.png" alt="License" title="License" height="16"></a>.
</p>
</footer>
<div id="st"></div>
</body>
</html>

View File

@ -1,39 +1,34 @@
#This file is (C) Captain ALM
#Under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License
cssBaseURL: "resources/assets/base.css"
cssDarkURL: "resources/assets/dark.css"
cssLightURL: "resources/assets/light.css"
jScriptURL: "resources/assets/index.js"
noVideoImageLocation: "resources/assets/novideo.png"
playVideoImageLocation: "resources/assets/video.png"
logoImageLocation: "resources/assets/logo.png"
moonImageLocation: "resources/assets/moon.png"
sunImageLocation: "resources/assets/sun.png"
sortImageLocation: "resources/assets/sort.png"
cssBaseURL: "https://cityuni.captainalm.com/resources/assets/base.css"
cssDarkURL: "https://cityuni.captainalm.com/resources/assets/dark.css"
cssLightURL: "https://cityuni.captainalm.com/resources/assets/light.css"
jScriptURL: "https://cityuni.captainalm.com/resources/assets/index.js"
noVideoImageLocation: "https://cityuni.captainalm.com/resources/assets/novideo.png"
playVideoImageLocation: "https://cityuni.captainalm.com/resources/assets/video.png"
logoImageLocation: "https://cityuni.captainalm.com/resources/assets/logo.png"
moonImageLocation: "https://cityuni.captainalm.com/resources/assets/moon.png"
sunImageLocation: "https://cityuni.captainalm.com/resources/assets/sun.png"
sortImageLocation: "https://cityuni.captainalm.com/resources/assets/sort.png"
headerLinks:
Main Portfolio: "https://portfolio.captainalm.com/"
Root Site Home: "https://www.captainalm.com/"
LinkedIn: "https://www.linkedin.com/in/alfred-manville/"
Github: "https://github.com/Captain-ALM/"
about:
title: "Alfred Manville (Captain ALM)"
content: >
<p>
Hello, I'm Alfred Manville (#age# Years Old) and a third year student at City, University of London.
Hello, I'm Alfred Manville (#age# Years Old).
I'm a free and open-source developer who enjoys networking my laptops together,
writes network software to communicate between them and then tries to break said software.
I also have a <a href="https://youtube.com/c/CaptainALM">Youtube Channel</a> which is in the process of being resumed from a hiatus.
</p>
<p>
On the programming side, I know Visual Basic .net, C# .net, C, Java, Go, Javascript, C++, Python, Bash,
Haskell, Processing and Microsoft Smallbasic (I have also dabbled in Batch).
I am currently in the progress of writing infrastructure software in Go, in the past, I wrote a <a href="https://github.com/Captain-ALM/CALM-Console">command console</a>
in VB .net for my own pluggable libraries (I created a CMD emulator to get past the school disabling interactive CMD) and some <a href="https://github.com/Captain-ALM/CALMNetLibSamples">
network communication applications</a> (Including a peer-to-peer <a href="https://github.com/Captain-ALM/C-ALM-VOIP">VOIP client</a>
using NAudio as the audio library and my own network wrapper library, however, it is in need of bug-fixing at the moment).
</p>
<p>
My github username is <a href="https://github.com/Captain-ALM">Captain-ALM</a> and has half my public programming projects,
the other half is located at: <a href="https://code.mrmelon54.com/alfred">https://code.mrmelon54.com/alfred</a>
On the programming side, I know Visual Basic .net, C# .net, C, Java, Go, Javascript (Circa. 2000), Processing and Microsoft Smallbasic
(I have also dabbled in C++, Python and Bash/Batch).
I am currently in the progress of writing infrastructure software in Go, in the past, I wrote a command console in VB .net for my own
pluggable libraries (I created a CMD emulator to get past the school disabling interactive CMD) and some network communication applications
(Including a peer-to-peer VOIP client using NAudio as the audio library and my own network wrapper library).
</p>
<p>
On the cracking / hacking side, I've used virtual machines a lot (Mainly infrastructure testing
@ -41,25 +36,19 @@ about:
I've also used VMs to pull perform a PXE boot off a network and analyse the partially deployed image
(And this is why the deployment servers should be switched off when unneeded, especially since PXE
auto-domain-join would store its credentials in the image).
I also played around with <a href="https://github.com/Captain-ALM/rdpccgs-ccgsrdp-">accessing the RDP servers</a>
when I was in secondary school (Turns out remote apps is just a glorified application auto-launcher with window size detection).
Here is <a href="https://github.com/Captain-ALM/op_ctrl">Operation Control</a> (Stylized: op_ctrl) used for same-computer exploiting
by wrapping target applications run by other users (Such as via RDP Remote Apps) and then starting a master server to send arbitrary
.net DLLs to execute on the target slaved client.
I also played around with accessing the RDP servers when I was in secondary school (Turns out remote apps
is just a glorified application auto-launcher with window size detection).
</p>
<p>
I also <a href="https://subsection.captainalm.com/">bake bread</a> (Mostly learnt from my grandma); although this sub-site is still under construction.
I also play video-games (Check my Youtube Channel or my <a href="https://www.gog.com/u/Captain_ALM">GOG Profile</a>) and am an expert at using lower-end hardware.
I also <a href="https://subsection.captainalm.com/">bake bread</a> although this sub-site is still under construction (Mostly learnt from my grandma).
I also play video-games and am an expert at using lower-end hardware.
</p>
<p>
I used to do Karate (Kyokushin Brown Belt) and I wish I could still fit my bike.
Here is my <a href="https://cdn.captainalm.com/download/keys/alfred@captainalm.com.asc">GPG Key</a> for my email address.
My <a href="https://cdn.captainalm.com/download/keys/alfred@captainalm.com.asc">GPG Key</a> for my email address.
</p>
<p>
My CV is available in the following formats: ( <a href="https://cdn.captainalm.com/download/cvs/AlfredManvilleCV-2024.docx">DOCX</a> | <a href="https://cdn.captainalm.com/download/cvs/AlfredManvilleCV-2024.pdf">PDF</a> )
</p>
thumbnailLocation: "resources/assets/imageofyou_t.jpg"
imageLocation: "resources/assets/imageofyou.jpg"
thumbnailLocation: "https://cityuni.captainalm.com/resources/assets/imageofyou_t.jpg"
imageLocation: "https://cityuni.captainalm.com/resources/assets/imageofyou.jpg"
imageAltText: "Image of me."
birthYear: 2002
contactEmail: "alfred@captainalm.com"
@ -82,35 +71,22 @@ entries:
<p>
Here is the repo: <a href="https://github.com/Captain-ALM/Ninjaformer-Processing">https://github.com/Captain-ALM/Ninjaformer-Processing</a>
</p>
<p>
The original video is available here: <a href="resources/stream/vid1.mp4">resources/stream/vid1.mp4</a>
</p>
startDate: "01/10/2021"
endDate: "31/10/2021"
videoLocation: "resources/stream/vid-bootcamp.mp4"
videoLocation: "https://cityuni.captainalm.com/resources/stream/vid1.mp4"
videoContentType: "video/mp4"
videoThumbnailLocation: "resources/assets/bootcamp-vid.png"
thumbnailLocations:
- "resources/assets/pic1_t.jpg"
- "resources/assets/pic2_t.jpg"
- "resources/assets/pic3_t.jpg"
- "resources/assets/bootcamp-1_t.jpg"
- "resources/assets/bootcamp-2_t.jpg"
- "resources/assets/bootcamp-3_t.jpg"
- "https://cityuni.captainalm.com/resources/assets/pic1_t.png"
- "https://cityuni.captainalm.com/resources/assets/pic2_t.png"
- "https://cityuni.captainalm.com/resources/assets/pic3_t.png"
imageLocations:
- "resources/assets/pic1.jpg"
- "resources/assets/pic2.jpg"
- "resources/assets/pic3.jpg"
- "resources/assets/bootcamp-1.jpg"
- "resources/assets/bootcamp-2.jpg"
- "resources/assets/bootcamp-3.jpg"
- "https://cityuni.captainalm.com/resources/assets/pic1.png"
- "https://cityuni.captainalm.com/resources/assets/pic2.png"
- "https://cityuni.captainalm.com/resources/assets/pic3.png"
imageAltTexts:
- "Level select screen."
- "Empty content interface (Gameplay)."
- "Level editor screen."
- "Ninjagame source code."
- "Button image source code."
- "Sprite world source code."
- name: "City Game Project 2022: Ninjaformer (Alpha, Beta)"
content: >
<p>
@ -134,43 +110,24 @@ entries:
The final level allows the ninja to "complete" the game while exploring a set of caves.
</p>
<p>
The game contains a mechanism system allowing for the unlocking of portals (Doors) for the character to progress within and between levels.
The character contains a set of different stamina types, core stamina which if depleted causes a death, leg stamina which is a multiplier for
doing any action that uses legs and arm stamina which is a multiplier for doing any action that uses arms. The game contains a weapon system of
throwing stars, swords and throwable liquids.
</p>
<p>
Here is the repo: <a href="https://github.com/cityteaching/citygame2122-Captain-ALM"><strike><del>Not public due to university anti-plagiarism policy.</del></strike></a>
</p>
<p>
The original video is available here: <a href="resources/stream/vid2.mp4">resources/stream/vid2.mp4</a>
</p>
startDate: "25/02/2022"
endDate: "08/05/2022"
videoLocation: "resources/stream/vid-ninjaformer-2022.mp4"
videoLocation: "https://cityuni.captainalm.com/resources/stream/vid2.mp4"
videoContentType: "video/mp4"
videoThumbnailLocation: "resources/assets/ninjaformer-vid.png"
thumbnailLocations:
- "resources/assets/pic4_t.jpg"
- "resources/assets/pic5_t.jpg"
- "resources/assets/pic6_t.jpg"
- "resources/assets/ninjaformer-1_t.jpg"
- "resources/assets/ninjaformer-2_t.jpg"
- "resources/assets/ninjaformer-3_t.jpg"
- "https://cityuni.captainalm.com/resources/assets/pic4_t.png"
- "https://cityuni.captainalm.com/resources/assets/pic5_t.png"
- "https://cityuni.captainalm.com/resources/assets/pic6_t.png"
imageLocations:
- "resources/assets/pic4.jpg"
- "resources/assets/pic5.jpg"
- "resources/assets/pic6.jpg"
- "resources/assets/ninjaformer-1.jpg"
- "resources/assets/ninjaformer-2.jpg"
- "resources/assets/ninjaformer-3.jpg"
- "https://cityuni.captainalm.com/resources/assets/pic4.png"
- "https://cityuni.captainalm.com/resources/assets/pic5.png"
- "https://cityuni.captainalm.com/resources/assets/pic6.png"
imageAltTexts:
- "Cave level."
- "Tutorial level."
- "Training level (Editor mode)."
- "Main Menu screen."
- "Pause Menu screen."
- "Audio Settings screen."
- "Training level."
- name: "Global Game Jam January 2022 : Shadow work"
content: >
<p>
@ -181,37 +138,12 @@ entries:
Read about and get the game files from: <a href="https://globalgamejam.org/2022/games/shadow-work-8">https://globalgamejam.org/2022/games/shadow-work-8</a>
</p>
<p>
Download the windows executable from: <a href="https://cdn.captainalm.com/download/game/dist/ShadowWorkExecutable.zip">https://cdn.captainalm.com/download/game/dist/ShadowWorkExecutable.zip</a>
</p>
<p>
The Design Document is available here: <a href="https://cdn.captainalm.com/download/game/design/Shadow-WIP-Story-Info.pdf">https://cdn.captainalm.com/download/game/design/Shadow-WIP-Story-Info.pdf</a>
Download the windows executable from: <a href="https://cdn.captainalm.com/download/ShadowWorkExecutable.zip">https://cdn.captainalm.com/download/ShadowWorkExecutable.zip</a>
</p>
startDate: "20/01/2022"
endDate: "30/01/2022"
videoLocation: "resources/stream/vid-shadowwork.mp4"
videoContentType: "video/mp4"
videoThumbnailLocation: "resources/assets/shadowwork-vid.png"
thumbnailLocations:
- "resources/assets/shadowwork-2_t.jpg"
- "resources/assets/shadowwork-3_t.jpg"
- "resources/assets/shadowwork-4_t.jpg"
- "resources/assets/shadowwork-5_t.jpg"
- "resources/assets/shadowwork-6_t.jpg"
- "resources/assets/shadowwork-1_t.jpg"
imageLocations:
- "resources/assets/shadowwork-2.jpg"
- "resources/assets/shadowwork-3.jpg"
- "resources/assets/shadowwork-4.jpg"
- "resources/assets/shadowwork-5.jpg"
- "resources/assets/shadowwork-6.jpg"
- "resources/assets/shadowwork-1.jpg"
imageAltTexts:
- "Main Menu screen."
- "Controls screen."
- "Bedroom (Beginning game area)."
- "First Puzzle, duality keys."
- "Visualisation of in-game character split."
- "End of the game area."
#videoLocation: "https://cityuni.captainalm.com/resources/stream/vid3.mp4"
#videoContentType: "video/mp4"
- name: "City-University Portfolio"
content: >
<p>
@ -220,151 +152,10 @@ entries:
</p>
<p>
This project is under the BSD-3-Clause License, so if reusing, you must scrub references to me, the yml file this is written in is under
Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International <a href="https://creativecommons.org/licenses/by-nc-nd/4.0/">
<img src="https://mirrors.creativecommons.org/presskit/buttons/88x31/png/by-nc-nd.png" alt="License" height="16"></a>.
</p>
<p>
Find the source code here: <a href="https://code.mrmelon54.com/alfred/cityuni-webserver">https://code.mrmelon54.com/alfred/cityuni-webserver</a>
Find the source code here: <a href="https://code.mrmelon54.xyz/alfred/cityuni-webserver">https://code.mrmelon54.xyz/alfred/cityuni-webserver</a>
</p>
startDate: "13/07/2022"
- name: "Python Communicator"
content: >
<p>
After learning python for my portfolio development option, I wanted to showcase what I knew in python.
I usually make a network application in each of the new programming languages that I learn.
For the repo showing me learning python please go to: <a href="https://code.mrmelon54.com/alfred/LearningPy">https://code.mrmelon54.com/alfred/LearningPy</a>
</p>
<p>
This project is a message based network communicator written in python and has a module for networking.
The project allows the sending of text messages and files over a network.
It also comes with a nice twist, in that if you select the pickle protocol, you can inject code into another client by sending a specially crafted message!
</p>
<p>
Find the source code here: <a href="https://github.com/Captain-ALM/CALMPyNetworker">https://github.com/Captain-ALM/CALMPyNetworker</a>
</p>
startDate: "10/12/2022"
endDate: "10/12/2022"
videoLocation: "resources/stream/vid-pycom.mp4"
videoContentType: "video/mp4"
videoThumbnailLocation: "resources/assets/pycom-vid.png"
thumbnailLocations:
- "resources/assets/pycom-1_t.jpg"
- "resources/assets/pycom-2_t.jpg"
- "resources/assets/pycom-3_t.jpg"
- "resources/assets/pycom-4_t.jpg"
imageLocations:
- "resources/assets/pycom-1.jpg"
- "resources/assets/pycom-2.jpg"
- "resources/assets/pycom-3.jpg"
- "resources/assets/pycom-4.jpg"
imageAltTexts:
- "Text Messaging."
- "File Messaging."
- "Exploit Testing."
- "Failed Exploit Testing."
- name: "Group Project - AirVia ATS (AirTicket Sales)"
content: >
<p>
This group project was creating a Ticket Sales system for the fictional company AirVia LTD, for this the group had to both design the implementation and then write the code for it.
Unfortunately, the project was not finished to a state where all the required features were added in and while all of the backend functionality except for the reports existed,
the GUIs to view and control those backends was not available.
Examples of this include: Sales, Transactions, Discounts and Reports where no GUIs were created or finished for any of these components.
The design of the program was followed with a lot of adaptations (Rather than not being followed at all) and it architecturally made sense with the use of facade implementations;
The use of facade allowed for other people to code against an interface while waiting for a controller to be finished which extended the interface.
</p>
<p>
The database system was handled via an abstraction layer I designed and wrote myself which supports 'locking' a record for keeping consistency when multiple instances of the program are running.
This system uses an auxiliary table that has only the primary key column, a record is locked if it does not exist in the auxiliary table (Cannot delete) and is not locked if it does (Cannot insert);
This allows for atomic locking and unlocking of the record.
The implementation requires the record locked for safe access (Loading, Storing).
The abstraction layer makes use of two base classes, one for a single record and one for a table; with tha table one allowing the creation and deletion of the extending table via a schema and name being provided (As seen in the source code).
I also developed a backup system for the database that supports any table with the specifically supported data types used in the tables defined in the schema - removing the need to use third-party programs like SQLDump.
</p>
<p>
In the end, the following features were implemented: Login, Help / Error / Status Bar, Account System + GUI, Blank Types + GUI, Blanks + GUI, Customers + GUI, Discounts, Flexible Discounts, Sales, Transactions, Refunds, Dashboard + Notifications, Database Interfacing + Backup and Rates + GUI.
</p>
<p>
Find the source code here: <a href="https://github.com/karansambee/IN2018-Team-Project/tree/master">https://github.com/karansambee/IN2018-Team-Project/tree/master</a>
</p>
startDate: "01/02/2023"
endDate: "30/04/2023"
videoLocation: "resources/stream/vid-groupproject-2023.mp4"
videoContentType: "video/mp4"
videoThumbnailLocation: "resources/assets/groupproject-vid.png"
thumbnailLocations:
- "resources/assets/groupproject-1_t.jpg"
- "resources/assets/groupproject-2_t.jpg"
- "resources/assets/groupproject-3_t.jpg"
- "resources/assets/groupproject-4_t.jpg"
- "resources/assets/groupproject-5_t.jpg"
- "resources/assets/groupproject-6_t.jpg"
- "resources/assets/groupproject-7_t.jpg"
- "resources/assets/groupproject-8_t.jpg"
- "resources/assets/groupproject-9_t.jpg"
- "resources/assets/groupproject-10_t.jpg"
imageLocations:
- "resources/assets/groupproject-1.png"
- "resources/assets/groupproject-2.png"
- "resources/assets/groupproject-3.png"
- "resources/assets/groupproject-4.png"
- "resources/assets/groupproject-5.png"
- "resources/assets/groupproject-6.png"
- "resources/assets/groupproject-7.png"
- "resources/assets/groupproject-8.png"
- "resources/assets/groupproject-9.png"
- "resources/assets/groupproject-10.png"
imageAltTexts:
- "Logon Interface."
- "Administrator Dashboard Interface."
- "Blank Modifier."
- "Customer Creator."
- "Disabling an Account."
- "Rate Creator."
- "Blank Type Editor."
- "Help on Force Unlocking (Database Manager Interface)."
- "Account Editor on a Manager within The Dashboard Interface."
- "Part of the Main.java source code Screenshot."
- name: "City-University Promotional Video"
content: >
<p>
Here, I star in an interview for City, University of London's Promotional Marketing Campaign. Join <a href="https://www.city.ac.uk/">City</a>!
</p>
<p>
Find the video here: <a href="https://www.youtube.com/watch?v=tOccImgskec">https://www.youtube.com/watch?v=tOccImgskec</a>
</p>
<p>
Find the general School of Science and Technology video here: <a href="https://www.youtube.com/watch?v=pkTCf4CWFSY">https://www.youtube.com/watch?v=pkTCf4CWFSY</a>
</p>
startDate: "05/06/2023"
endDate: "05/06/2023"
videoLocation: "https://www.youtube.com/watch?v=tOccImgskec"
videoContentType: "text/uri-list"
videoThumbnailLocation: "resources/assets/citypromo-vid.png"
- name: "Decide Quiz - GCloud City"
content: >
<p>
This project was <a href="https://cdn.captainalm.com/download/gcloudcity/CloudApplicationSpecification-AlfredManville-MohammadMasood.docx">designed</a> <a href="https://cdn.captainalm.com/download/gcloudcity/CloudPresentation-AlfredManville-MohammadMasood.pptx">to</a> operate as a Kahoot clone although the front-end never got completed by the other member of the pair (This was written in React).
</p>
<p>
This was created in a pair as part of the Cloud Computing module at City, University of London. It was built for use using google cloud and therefore
uses many Google Cloud Platform Technologies which are listed and shown off in the video.
</p>
<p>
The communication protocol uses JSON packets passed either through a WebSocket connection or a REST based protocol that polls the server for data while sending the queued packets.
The REST connection is used as a fallback system where WebSockets do not work; in addition, a REST connection is made to the master server to first work out which app server has
the least load, once found, this is sent back to the client where the client will then attempt a WebSocket connection and, on failure, a REST session is created (A key is returned
which is then used as a parameter in subsequent communications). In the event there is no more capacity, a service unavailable error is sent and a new VM will be spun up, in the case
that any are left. The source code for this library can be found at <a href="https://github.com/Captain-ALM/gc-c-com">https://github.com/Captain-ALM/gc-c-com</a> and the master server source
code can be found at <a href="https://github.com/Captain-ALM/gc-c-master-srv">https://github.com/Captain-ALM/gc-c-master-srv</a>.
</p>
<p>
The main game loop was supposed to allow user generated quizzes once logged in along-side allowing for public quizzes that could be used and copied by other users.
Only logged in users could start games where any user - both logged in or not - could join and answer questions within a set amount of time, with the person answering
the fastest getting more points than people who answer later. The system would also have a leaderboard shown at the end of each question; it was also designed to recover
from crashes and resume from the last question executed. The source code for the app server can be found at <a href="https://github.com/Captain-ALM/gc-c-app-srv">
https://github.com/Captain-ALM/gc-c-app-srv</a> where all this functionality does exist in the backend; the database source code can be found at <a href="https://github.com/Captain-ALM/gc-c-db">https://github.com/Captain-ALM/gc-c-db</a>.
</p>
startDate: "27/11/2023"
endDate: "14/01/2024"
videoLocation: "resources/stream/vid-gc-c-v2.mp4"
videoContentType: "video/mp4"
videoThumbnailLocation: "resources/assets/vid-gc-c-v2.png"

170
index.js
View File

@ -12,9 +12,9 @@ var OrderValue = ""
function SetupJS() {
SetupIndexArray()
SetupJSTheme()
SetupJSHPL()
SetupJSHSO()
SetupJSSOI()
SetupJSRSN()
}
function CreateEntry(id, name, videourl, videotype, start, end, duration) {
EntryData[id] = {
@ -26,9 +26,9 @@ function CreateEntry(id, name, videourl, videotype, start, end, duration) {
duration : parseInt(duration, 10)
};
}
function CreateVideoPlaceholder(id,phImageURL) {
function CreateVideoPlaceholder(id) {
var imgPH = document.createElement("img")
imgPH.src = phImageURL
imgPH.src = PlayImageURL
imgPH.id = "play-"+id
imgPH.alt = "Play Video"
imgPH.title = "Play"
@ -67,19 +67,38 @@ function SetupIndexArray() {
function SetupJSTheme() {
var th = document.getElementById("theme")
th.href = "#"
new Image().src = MoonImageURL //Preload I hope
if (document.addEventListener) {
th.addEventListener("click", ToggleTheme)
th.addEventListener("click", CToggleTheme)
} else {
th.setAttribute("onclick", "ToggleTheme();")
th.onclick = ToggleTheme
th.setAttribute("onclick", "CToggleTheme();")
th.onclick = CToggleTheme
}
}
function cReplaceHistory() {
ReplaceHistory(window.location.href)
}
function ReplaceHistory(url) {
var s = true
if (window.history) {
if (window.history.replaceState) {
window.history.replaceState({}, "", url)
window.history.replaceState({
light: !!document.getElementById("so-theme"),
order: document.getElementById("so-order").value,
sort: document.getElementById("so-sort").value
}, "", url);
console.log("REPLACE")
}
}
}
function PushHistory(url) {
var s = true
if (window.history) {
if (window.history.pushState) {
window.history.pushState({
light: !!document.getElementById("so-theme"),
order: document.getElementById("so-order").value,
sort: document.getElementById("so-sort").value
}, "", url);
console.log("PUSH")
s = false
}
}
@ -87,7 +106,11 @@ function ReplaceHistory(url) {
document.location.href = url
}
}
function ToggleTheme() {
function CToggleTheme() {
ToggleTheme(true)
}
function ToggleTheme(p) {
if (p) {cReplaceHistory();}
var th = document.getElementById("theme")
var thimg = document.getElementById("theme-img")
var thsty = document.getElementById("style-theme")
@ -100,7 +123,7 @@ function ToggleTheme() {
th.title = "Switch to Light Mode"
document.getElementById("so-form").removeChild(document.getElementById("so-theme"))
logo.href = "?"
ReplaceHistory(url+"?"+TheParameters+"#")
if (p) {PushHistory(url+"?"+TheParameters+"#");}
thsty.href = CssDarkURL
} else {
thimg.src = MoonImageURL
@ -112,14 +135,37 @@ function ToggleTheme() {
thi.id = "so-theme"
document.getElementById("so-form").appendChild(thi)
logo.href = "?light"
if (TheParameters === "") {
ReplaceHistory(url+"?light#")
} else {
ReplaceHistory(url+"?light&"+TheParameters+"#")
if (p) {
if (TheParameters === "") {
PushHistory(url + "?light#")
} else {
PushHistory(url + "?light&" + TheParameters + "#")
}
}
thsty.href = CssLightURL
}
}
function SetupJSHPL(){
if (window.history) {
if (window.history.pushState && window.history.replaceState) {
//document.addEventListener("DOMContentLoaded", cReplaceHistory)
window.addEventListener("popstate", HandleHistoryPop)
}
}
}
function HandleHistoryPop(event) {
console.log("POP")
console.log(event.state)
if (event.state) {
SortOrderEnabled = false
var isnl = !document.getElementById("so-theme")
if ((event.state.light && isnl) || (!event.state.light && !isnl)) {ToggleTheme(false);}
document.getElementById("so-order").value = event.state.order
document.getElementById("so-sort").value = event.state.sort
EntrySort(event.state.order, event.state.sort, false)
SortOrderEnabled = true
}
}
function SetupJSHSO() {
var pb = document.getElementById("sort-menu-button")
var pane = document.getElementById("so-pane")
@ -176,9 +222,9 @@ function SetupJSSOI() {
SortOrderEnabled = true
}
function HandleSortOrderChange() {
if (SortOrderEnabled) {EntrySort(document.getElementById("so-order").value, document.getElementById("so-sort").value);}
if (SortOrderEnabled) {EntrySort(document.getElementById("so-order").value, document.getElementById("so-sort").value, true);}
}
function EntrySort(o, s) {
function EntrySort(o, s, p) {
var ts = s.toString().toLowerCase()
var chg = false
if (SortValue !== s) {
@ -186,10 +232,10 @@ function EntrySort(o, s) {
SortValue = s
}
if (chg || OrderValue !== o) {
if (ts === "asc" || ts === "ascending") {
ts = 1
} else {
if (ts === "desc" || ts === "descending") {
ts = -1
} else {
ts = 1
}
var to = o.toString().toLowerCase()
if (to === "start") {
@ -224,10 +270,12 @@ function EntrySort(o, s) {
TheParameters = "order="+OrderValue+"&sort="+SortValue
var url = document.location.href
url = url.split("#", 1)[0].split('?', 1)[0]
if (document.getElementById("so-theme")) {
ReplaceHistory(url+"?light&"+TheParameters)
} else {
ReplaceHistory(url+"?"+TheParameters)
if (p) {
if (document.getElementById("so-theme")) {
PushHistory(url + "?light&" + TheParameters)
} else {
PushHistory(url + "?" + TheParameters)
}
}
for (var i = 0; i < EntryIndices.length; i++) {
var tNode = document.getElementById("entry-"+EntryIndices[i])
@ -292,78 +340,4 @@ function SortDurationD(a, b) {
} else {
return 1
}
}
function SetupJSRSN() {
if (window.addEventListener) {
window.addEventListener("resize", PerformNavResize)
} else {
window.setAttribute("onresize", "PerformNavResize();")
window.onresize = PerformNavResize
}
PerformNavResize()
}
function PerformNavResize() {
var ww = 0
if (window.innerWidth && window.innerWidth !== 10) {
ww = window.innerWidth
} else {
var ht = document.getElementsByTagName("html")
if (ht && ht.length > 0) {ww = ht[0].clientWidth;}
}
if (ww > 0) {
var maxbarsz = ww - 342;
var men = document.getElementById("menu")
var vmen = document.getElementById("vmenu")
if (men && vmen) {
if (ww > 679) {
while (vmen.childNodes.length > 0) {InsertBefore(men, vmen.removeChild(vmen.childNodes[vmen.childNodes.length - 1]));}
} else {
var vmeni
var mensz = 0
var menc = []
var imenc = 0
for (vmeni = 0; vmeni < vmen.childNodes.length; vmeni++) {
if (vmen.childNodes[vmeni].nodeType === Node.ELEMENT_NODE) {
if (mensz+vmen.childNodes[vmeni].clientWidth > maxbarsz) {menc[imenc] = vmen.childNodes[vmeni]; imenc++;}
mensz += vmen.childNodes[vmeni].clientWidth
}
}
if (menc.length > 0) {
for (vmeni = 0; vmeni < menc.length; vmeni++) {vmen.removeChild(menc[vmeni]);}
for (vmeni = menc.length - 1; vmeni >= 0; vmeni--) {InsertBefore(men, menc[vmeni]);}
} else {
for (vmeni = 0; vmeni < men.childNodes.length; vmeni++) {
if (men.childNodes[vmeni].nodeType === Node.ELEMENT_NODE) {
var mena = GetFirstSubElement(men.childNodes[vmeni], 0)
var menaw = GetNavTextWidth(mena.textContent)
if (mensz+menaw <= maxbarsz) {menc[imenc] = men.childNodes[vmeni]; imenc++;}
mensz += menaw
}
}
for (vmeni = 0; vmeni < menc.length; vmeni++) {vmen.appendChild(men.removeChild(menc[vmeni]));}
}
}
}
}
}
function GetFirstSubElement(t,r) {
for (var gfsei = 0; gfsei < t.childNodes.length; gfsei++) {
if (t.childNodes[gfsei].nodeType === Node.ELEMENT_NODE) {
if (r < 1) {return t.childNodes[gfsei];} else {return GetFirstSubElement(t.childNodes[gfsei], r - 1);}
}
}
return t
}
function InsertBefore(p,c) {
if (p.childNodes.length > 0) {p.insertBefore(c, p.childNodes[0]);} else {p.appendChild(c);}
}
function GetNavTextWidth(s) {
var st = document.getElementById("st")
if (st) {
st.textContent = s
var trw = st.clientWidth
st.textContent = ""
return trw
}
return 8 * s.length + 32
}

View File

@ -10,13 +10,13 @@ body{
a{
color: #4f4fff;
}
.header, nav, footer, .so-pane{
.header, .nav, footer, .so-pane{
background-color: #e2e2e1;
}
.home-button > div, .sort-button > div, .menu a, .vmenu a, .so-pane > form > div > * > *{
.home-button > div, .sort-button > div, .menu a, .so-pane > form > div > * > *{
color: #1f1f1f;
}
.home-button:hover, .menu a:hover, .vmenu a:hover, .hmb:hover, .sort-button:hover, .sort-menu:checked ~ .sort-button, .sort-button-active, .so-pane > form > div > span > input, .so-pane > form > div > div > select{
.home-button:hover, .menu a:hover, .hmb:hover, .sort-button:hover, .sort-menu:checked ~ .sort-button, .sort-button-active, .so-pane > form > div > span > input, .so-pane > form > div > div > select{
background-color: #9f9f9e;
}
.hmb-line, .hmb-line::before, .hmb-line::after{

View File

@ -45,7 +45,6 @@ func (gipg *goInfoPage) GetCacheIDExtension(urlParameters url.Values) string {
type goInfoTemplateMarshal struct {
FullOutput bool
CurrentTime time.Time
RegisteredPages []string
CachedPages []string
ProcessID int
@ -99,7 +98,6 @@ func (gipg *goInfoPage) GetContents(urlParameters url.Values) (contentType strin
theBuffer := &io.BufferedWriter{}
err = theTemplate.ExecuteTemplate(theBuffer, templateName, &goInfoTemplateMarshal{
FullOutput: urlParameters.Has("full"),
CurrentTime: time.Now(),
RegisteredPages: regPages,
CachedPages: cacPages,
ProcessID: os.Getpid(),

View File

@ -43,9 +43,9 @@ func NewPageHandler(config conf.ServeYaml) *PageHandler {
CacheSettings: config.CacheSettings,
}
if config.EnableGoInfoPage {
toReturn.PageProviders = GetProviders(config.CacheSettings.EnableTemplateCaching, config.GetDataStoragePath(), toReturn, config.GetTemplateStoragePath(), config.PageSettings, config.YmlDataFallback)
toReturn.PageProviders = GetProviders(config.CacheSettings.EnableTemplateCaching, config.DataStorage, toReturn)
} else {
toReturn.PageProviders = GetProviders(config.CacheSettings.EnableTemplateCaching, config.GetDataStoragePath(), nil, config.GetTemplateStoragePath(), config.PageSettings, config.YmlDataFallback)
toReturn.PageProviders = GetProviders(config.CacheSettings.EnableTemplateCaching, config.DataStorage, nil)
}
return toReturn
}
@ -286,9 +286,6 @@ func (ph *PageHandler) GetRegisteredPages() []string {
}
func (ph *PageHandler) GetCachedPages() []string {
if ph.pageContentsCacheRWMutex == nil {
return make([]string, 0)
}
ph.pageContentsCacheRWMutex.RLock()
defer ph.pageContentsCacheRWMutex.RUnlock()
pages := make([]string, len(ph.PageContentsCache))
@ -301,9 +298,6 @@ func (ph *PageHandler) GetCachedPages() []string {
}
func (ph *PageHandler) GetNumberOfCachedPages() int {
if ph.pageContentsCacheRWMutex == nil {
return 0
}
ph.pageContentsCacheRWMutex.RLock()
defer ph.pageContentsCacheRWMutex.RUnlock()
return len(ph.PageContentsCache)

View File

@ -1,26 +1,18 @@
package pageHandler
import (
"golang.captainalm.com/cityuni-webserver/conf"
"golang.captainalm.com/cityuni-webserver/pageHandler/pages/index"
"strings"
)
import "golang.captainalm.com/cityuni-webserver/pageHandler/pages/index"
var providers map[string]PageProvider
func GetProviders(cacheTemplates bool, dataStorage string, pageHandler *PageHandler, templateStorage string, pageSettings []conf.PageYaml, ymlDataFallback bool) map[string]PageProvider {
func GetProviders(cacheTemplates bool, dataStorage string, pageHandler *PageHandler) map[string]PageProvider {
if providers == nil {
providers = make(map[string]PageProvider)
if pageHandler != nil {
infoPage := newGoInfoPage(pageHandler, dataStorage, cacheTemplates)
providers[infoPage.GetPath()] = infoPage //Go Information Page
}
for _, cpg := range pageSettings { //Register pages
if strings.EqualFold(cpg.PageName, index.PageName) {
indexPage := index.NewPage(dataStorage, cacheTemplates, templateStorage, cpg.GetPagePath(), ymlDataFallback)
providers[indexPage.GetPath()] = indexPage
}
}
indexPage := index.NewPage(dataStorage, cacheTemplates)
providers[indexPage.GetPath()] = indexPage
}
return providers
}

View File

@ -5,23 +5,21 @@ import (
"html/template"
"math"
"net/http"
"strings"
"time"
)
const dateFormat = "01/2006"
type EntryYaml struct {
Name string `yaml:"name"`
Content string `yaml:"content"`
StartDate yaml.DateType `yaml:"startDate"`
EndDate yaml.DateType `yaml:"endDate"`
VideoLocation template.URL `yaml:"videoLocation"`
VideoContentType string `yaml:"videoContentType"`
ThumbnailLocations []template.URL `yaml:"thumbnailLocations"`
ImageLocations []template.URL `yaml:"imageLocations"`
ImageAltTexts []string `yaml:"imageAltTexts"`
VideoThumbnailLocation template.URL `yaml:"videoThumbnailLocation"`
Name string `yaml:"name"`
Content string `yaml:"content"`
StartDate yaml.DateType `yaml:"startDate"`
EndDate yaml.DateType `yaml:"endDate"`
VideoLocation template.URL `yaml:"videoLocation"`
VideoContentType string `yaml:"videoContentType"`
ThumbnailLocations []template.URL `yaml:"thumbnailLocations"`
ImageLocations []template.URL `yaml:"imageLocations"`
ImageAltTexts []string `yaml:"imageAltTexts"`
}
type ImageReference struct {
@ -30,18 +28,6 @@ type ImageReference struct {
ImageAltText string
}
func (ey EntryYaml) GetVideoThumbnail(usual template.URL) template.URL {
if ey.VideoThumbnailLocation == "" {
return usual
} else {
return ey.VideoThumbnailLocation
}
}
func (ey EntryYaml) IsVideoLink() bool {
return strings.EqualFold(ey.VideoContentType, "text/uri-list")
}
func (ey EntryYaml) GetStartDate() string {
return ey.StartDate.Format(dateFormat)
}

View File

@ -1,7 +1,6 @@
package index
import (
"errors"
"golang.captainalm.com/cityuni-webserver/utils/io"
"gopkg.in/yaml.v3"
"html/template"
@ -13,10 +12,10 @@ import (
"time"
)
const PageName = "index"
const templateName = "index.go.html"
const yamlName = "index.go.yml"
func NewPage(dataStore string, cacheTemplates bool, templateStore string, pagePath string, ymlDataFallback bool) *Page {
func NewPage(dataStore string, cacheTemplates bool) *Page {
var ptm *sync.Mutex
var sdm *sync.Mutex
if cacheTemplates {
@ -24,10 +23,7 @@ func NewPage(dataStore string, cacheTemplates bool, templateStore string, pagePa
sdm = &sync.Mutex{}
}
pageToReturn := &Page{
YMLDataFallback: ymlDataFallback,
PagePath: pagePath,
DataPath: path.Join(dataStore, pagePath),
TemplatePath: path.Join(templateStore, templateName),
DataStore: dataStore,
StoredDataMutex: sdm,
PageTemplateMutex: ptm,
}
@ -35,10 +31,7 @@ func NewPage(dataStore string, cacheTemplates bool, templateStore string, pagePa
}
type Page struct {
YMLDataFallback bool
PagePath string
DataPath string
TemplatePath string
DataStore string
StoredDataMutex *sync.Mutex
StoredData *DataYaml
LastModifiedData time.Time
@ -48,7 +41,7 @@ type Page struct {
}
func (p *Page) GetPath() string {
return p.PagePath
return "/index.go"
}
func (p *Page) GetLastModified() time.Time {
@ -136,12 +129,16 @@ func (p *Page) getPageTemplate() (*template.Template, error) {
defer p.PageTemplateMutex.Unlock()
}
if p.PageTemplate == nil {
stat, err := os.Stat(p.TemplatePath)
thePath := templateName
if p.DataStore != "" {
thePath = path.Join(p.DataStore, thePath)
}
stat, err := os.Stat(thePath)
if err != nil {
return nil, err
}
p.LastModifiedTemplate = stat.ModTime()
loadedData, err := os.ReadFile(p.TemplatePath)
loadedData, err := os.ReadFile(thePath)
if err != nil {
return nil, err
}
@ -164,18 +161,13 @@ func (p *Page) getPageData() (*DataYaml, error) {
defer p.StoredDataMutex.Unlock()
}
if p.StoredData == nil {
thePath := p.DataPath
thePath := yamlName
if p.DataStore != "" {
thePath = path.Join(p.DataStore, thePath)
}
stat, err := os.Stat(thePath)
if err != nil {
if p.YMLDataFallback && errors.Is(err, os.ErrNotExist) {
thePath += ".yml"
stat, err = os.Stat(thePath)
if err != nil {
return nil, err
}
} else {
return nil, err
}
return nil, err
}
p.LastModifiedData = stat.ModTime()
fileHandle, err := os.Open(thePath)
@ -197,16 +189,15 @@ func (p *Page) getPageData() (*DataYaml, error) {
p.StoredData = dataYaml
}
return dataYaml, nil
} else {
return p.StoredData, nil
}
}
func getSortValue(toCheckIn string) int8 {
if toCheckIn == "asc" || toCheckIn == "ascending" {
return 1
} else {
if toCheckIn == "desc" || toCheckIn == "descending" {
return -1
} else {
return 1
}
}