Commit c0e9a81b authored by Anders Benjamin Clausen's avatar Anders Benjamin Clausen 👽
Browse files

Merge branch 'develop' into 'feature/remove-blocks'

# Conflicts:
#   website/studerende-dk/src/views/Home.vue
parents 2bd201c4 e12a0098
Pipeline #52245 passed with stage
in 41 seconds
.DS_Store
\ No newline at end of file
.DS_Store
.vscode
\ No newline at end of file
stages:
- test
- create-vue-build
- build-docker-container
- build-docker-server-container
- build-docker-web-container
test:
stage: test
......@@ -16,7 +17,6 @@ test:
create-vue-build:
only:
# - master
- develop
stage: create-vue-build
image: node
......@@ -34,11 +34,26 @@ create-vue-build:
paths:
- website/studerende-dk/node_modules/
build-docker-container:
build-docker-server-container:
only:
# - master
- develop
stage: build-docker-container
stage: build-docker-server-container
image: docker:latest
services:
- name: docker:19.03.8-dind
before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
script:
- cd backend
- echo "Starting docker build of server."
- docker build . -t "$CI_REGISTRY_IMAGE""/server"
- docker push "$CI_REGISTRY_IMAGE""/server"
- echo "Docker build of server done!"
build-docker-web-container:
only:
- develop
stage: build-docker-web-container
image: docker:latest
services:
- name: docker:19.03.8-dind
......@@ -46,5 +61,7 @@ build-docker-container:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
script:
- cd website/studerende-dk
- docker build . -t "$CI_REGISTRY_IMAGE"
- docker push "$CI_REGISTRY_IMAGE"
- echo "Starting docker build of web."
- docker build . -t "$CI_REGISTRY_IMAGE""/web"
- docker push "$CI_REGISTRY_IMAGE""/web"
- echo "Docker build of web done!"
FROM python:3.8
COPY server/* .
ENV PYTHONUNBUFFERED=1
EXPOSE 1337
CMD ["python", "server.py"]
\ No newline at end of file
# Inspired by https://pythonbasics.org/webserver/
from http.server import BaseHTTPRequestHandler, HTTPServer
import time
hostName = '0.0.0.0'
serverPort = 1337
db = {
'katrine-marie' : '{"left":[],"right":[{"height":400,"blocks":[{"type":"Calendar","width":100}]}]}',
'isaac' : '{"left":[],"right":[{"height":400,"blocks":[{"type":"Feed","width":100}]}]}'
}
class MyServer(BaseHTTPRequestHandler):
def _set_ok_headers(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
def _set_err_headers(self):
self.send_response(500)
self.send_header('Content-type', 'text/html')
self.end_headers()
def handle_load_layout(self, id):
if id in db:
self._set_ok_headers()
self.wfile.write(bytes(db[id], 'utf-8'))
else:
self._set_err_headers()
self.wfile.write(bytes('Error: Could not find id ' + str(id), 'utf-8'))
def handle_save_layout(self, id, data):
db[id] = data.replace('%22', '"')
self._set_ok_headers()
def do_GET(self):
# remove '/?' from path
query = self.path[2:]
fields = dict(f.split("=") for f in query.split("&"))
if fields['type'] == "load":
self.handle_load_layout(fields['id'])
elif fields['type'] == "save":
self.handle_save_layout(fields['id'], fields['data'])
else:
self._set_err_headers()
self.wfile.write(bytes('Request type not supported', 'utf-8'))
if __name__ == '__main__':
webServer = HTTPServer((hostName, serverPort), MyServer)
print('Server started http://%s:%s' % (hostName, serverPort))
try:
webServer.serve_forever()
except KeyboardInterrupt:
pass
webServer.server_close()
print('Server stopped.')
\ No newline at end of file
# From https://docs.docker.com/compose/
version: "3.9"
services:
web:
build: website/studerende-dk/
ports:
- "80:80"
server:
build: backend/
ports:
- "1337:1337"
\ No newline at end of file
#!/bin/bash
# this script pulls the docker images and
# deploys them respectively if they are
# newer than the ones running.
# this script can be run at any time,
# and will only change the running
# containers if newer ones are available.
function deploy {
local url=$1
local service_name=$2
local run_arguments=$3
old_digest=$(docker inspect -f '{{.RepoDigests}}' ${url}:active | grep -o 'sha256:[0-9A-Fa-f]*')
# probably no existing image
if [ $? -ne 0 ]; then
echo "No existing image! Abort."
exit 1;
fi
new_digest=$(docker pull ${url}:latest | grep Digest | sed 's/Digest: //')
# network error or authentication might go wrong
if [ $? -ne 0 ]; then
echo "Auth or network err! Abort."
exit 2;
fi
# sanity check that new digest is formatted correctly and is same length as old.
# if it aint, it could be the result of a gitlab server error or such.
local check=$(echo $new_digest | grep -o 'sha256:[0-9A-Fa-f]*')
if [ "${#check}" -eq "0" ] || [ ${#old_digest} -ne 71 ]; then
echo "Damnit, something went bad! Crash and burn.."
exit 3;
fi
echo "Old digest: $old_digest"
echo "New digest: $new_digest"
if [ "$old_digest" != "$new_digest" ]; then
echo "Deploying new docker instance: $service_name."
docker stop $service_name
docker rm $service_name
docker rmi ${url}:active
docker tag ${url}:latest ${url}:active
docker run --network persist-net $run_arguments --name $service_name -d ${url}:active
result=0
else
echo "Already up to date."
fi
# remove/untag file. silence output
docker rmi ${url}:latest >/dev/null 2>&1
}
base_url="registry.gitlab.au.dk/exsys2021/da6/hold-afstand/"
# deploy new server if available
result=1
deploy ${base_url}server "server" "--network-alias server"
server_deployed=$result
echo
# deploy new web if available
result=1
deploy ${base_url}web "web" "-p 80:80"
web_deployed=$result
# if anything has been deployed, notify the devs
if [ $server_deployed -eq 0 ] || [ $web_deployed -eq 0 ]; then
[ $server_deployed -eq 0 ] && msg="backend"
[ $web_deployed -eq 0 ] && [ $server_deployed -eq 0 ] && msg=${msg}" and "
[ $web_deployed -eq 0 ] && msg=${msg}"frontend"
slack_msg="A new version of the ${msg} has been deployed! Check it out: https://vm34.exsys2021.cs.au.dk/"
echo $slack_msg
# notify slack channel
/home/auuser/slack-notifier.sh $slack_msg
fi
echo "Done."
#!/bin/bash
# ----- CAUTION!!! -----
# This script stops and removes the running web and server
# containers, removes their images and the persist-net
# docker network.
#
# It then reconfigures the network, download
# the images and redeploys them again.
base_url="registry.gitlab.au.dk/exsys2021/da6/hold-afstand/"
# stops docker containers
echo -n "Stopping containers..."
docker stop server >/dev/null 2>&1
docker stop web >/dev/null 2>&1
echo " Done."
# removes docker containers
echo -n "Removing containers..."
docker rm server >/dev/null 2>&1
docker rm web >/dev/null 2>&1
echo " Done."
# removes docker images
echo -n "Removing images..."
docker rmi ${base_url}server:active >/dev/null 2>&1
docker rmi ${base_url}web:active >/dev/null 2>&1
echo " Done."
# removes unused docker networks
echo -n "Removing docker network..."
docker network rm persist-net >/dev/null 2>&1
echo " Done."
# pulling the images
echo -n "Pulling latest sever image..."
docker pull ${base_url}server:latest >/dev/null 2>&1
echo " Done."
echo -n "Pulling latest web image..."
docker pull ${base_url}web:latest >/dev/null 2>&1
echo " Done."
# changes tags from latest to active
echo -n "Tagging..."
docker tag ${base_url}server:latest ${base_url}server:active >/dev/null 2>&1
docker tag ${base_url}web:latest ${base_url}web:active >/dev/null 2>&1
docker rmi ${base_url}server:latest >/dev/null 2>&1
docker rmi ${base_url}web:latest >/dev/null 2>&1
echo " Done."
# crates network
echo -n "Creates docker network..."
docker network create -d bridge persist-net --attachable >/dev/null 2>&1
echo " Done."
# spins up containers
echo -n "Spinning up containers..."
docker run --network persist-net --network-alias server --name server -d ${base_url}server:active >/dev/null 2>&1
docker run --network persist-net -p 80:80 --name web -d ${base_url}web:active >/dev/null 2>&1
echo " Done."
echo "All done!"
#!/bin/bash
# INFO: This script should be placed in auuser 's homefolder!
# sanity check
if [ "$#" == "0" ]; then
echo "The message should be passed as an argument!"
exit 1
fi
data='{"text":"'"$@"'"}'
url=$(head -n 1 slack-url)
curl -X POST -H 'Content-type: application/json' --data "$data" $url
FROM nginx:latest
COPY ./dist /usr/share/nginx/html
COPY nginx-conf/ /etc/nginx/conf.d/
\ No newline at end of file
##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# https://www.nginx.com/resources/wiki/start/
# https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
# https://wiki.debian.org/Nginx/DirectoryStructure
#
# In most cases, administrators will remove this file from sites-enabled/ and
# leave it as reference inside of sites-available where it will continue to be
# updated by the nginx packaging team.
#
# This file will automatically load configuration files provided by other
# applications, such as Drupal or Wordpress. These applications will be made
# available underneath a path with that package name, such as /drupal8.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##
# Default server configuration
#
server {
listen 80 default_server;
listen [::]:80 default_server;
# SSL configuration
#
# listen 443 ssl default_server;
# listen [::]:443 ssl default_server;
#
# Note: You should disable gzip for SSL traffic.
# See: https://bugs.debian.org/773332
#
# Read up on ssl_ciphers to ensure a secure configuration.
# See: https://bugs.debian.org/765782
#
# Self signed certs generated by the ssl-cert package
# Don't use them in a production server!
#
# include snippets/snakeoil.conf;
root /usr/share/nginx/html;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
server_name _;
location /persistence/ {
proxy_set_header X-NginX-Proxy true;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://server:1337/;
proxy_redirect off;
}
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
# pass PHP scripts to FastCGI server
#
#location ~ \.php$ {
# include snippets/fastcgi-php.conf;
#
# # With php-fpm (or other unix sockets):
# fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
# # With php-cgi (or other tcp sockets):
# fastcgi_pass 127.0.0.1:9000;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# Virtual Host configuration for example.com
#
# You can move that to a different file under sites-available/ and symlink that
# to sites-enabled/ to enable it.
#
#server {
# listen 80;
# listen [::]:80;
#
# server_name example.com;
#
# root /var/www/example.com;
# index index.html;
#
# location / {
# try_files $uri $uri/ =404;
# }
#}
\ No newline at end of file
......@@ -64,4 +64,8 @@
height: 100%;
}
.no-select{
@include no-select;
}
</style>
......@@ -15,4 +15,10 @@ export default {
}
}
}
</script>
\ No newline at end of file
</script>
<style scoped lang="scss">
.block{
min-width: 250px;
}
</style>
\ No newline at end of file
......@@ -21,6 +21,7 @@ export default {
.block {
width: 100%;
height: 100%;
min-width: 150px;
text-align: left;
display: flex;
flex-direction: column;
......
......@@ -175,6 +175,7 @@ export default {
</script>
<style lang="scss" scoped>
table{
width: 100%;
position: absolute;
......@@ -291,6 +292,7 @@ export default {
}
#calendar{
min-width: 250px;
width: 100%;
height: 100%;
position: relative;
......
......@@ -28,6 +28,10 @@ export default {
</script>
<style scoped lang="scss">
.block{
min-width: 350px;
}
ul {
margin-top: 8px;
}
......
......@@ -37,6 +37,10 @@ Any assumption that the word "same" means "same or different" is wrong and canno
</script>
<style scoped lang="scss">
.block{
min-width: 250px;
}
ul {
padding: 20px;
}
......
......@@ -2,7 +2,7 @@
<BlockTemplate heading="Post">
<ul>
<li v-for="(mail, index) in mails" :key="index">
<span>{{ mail.sender }}</span>
<span style="width: 50%;">{{ mail.sender }}</span>
<span class="send-date">{{ mail.date.toLocaleDateString('da-dk').replace(/\./g, '/') }}</span>
<br/>
<a class="subject" href="/about">{{ mail.subject }}</a>
......@@ -40,8 +40,14 @@ export default {
</script>
<style scoped lang="scss">
.block{
min-width: 250px;
}
ul {
margin-top: 8px;
//display: inline-block;
}
li:nth-child(even) {
......
......@@ -18,4 +18,4 @@ $white-bg-color: #fbfbfb;
$default-margin: 40px;
$mobile-width-cutoff: 992px;
\ No newline at end of file
$mobile-width-cutoff: 992px;
<template>
<div class="home">
<div id="grid">
<div class="row" v-for="(rowBlock, rowIndex) in layout" :key="rowIndex" :style="{ height: rowBlock.height + 'px' }" :id="rowIndex" @mouseleave="cancelRemoveRow(rowIndex)">
<div class="col" v-for="(colBlock, colIndex) in rowBlock.blocks" :key="colIndex" :style="{ 'flex-grow': colBlock.width } ">
<div class="row" v-for="(rowBlock, rowIndex) in layout" :key="rowIndex" :style="{ height: rowBlock.height + 'px' }" :id="rowIndex" @mouseleave="cancelRemoveRow(rowIndex)" @mousedown="resizeVertical($event, rowIndex)">
<div class="col" v-for="(colBlock, colIndex) in rowBlock.blocks" :key="colIndex" :style="{ 'flex-grow': colBlock.width }" @mousedown="resizeHorizontal($event, rowIndex, colIndex)">
<component :is="colBlock.type"></component>
<button class="hidden-row-item pencil">
<img v-svg-inline class="icon" src="@/assets/pencil.svg"/>
......@@ -32,6 +32,16 @@ import Feed from "@/components/blocks/Feed";
import Mail from "@/components/blocks/Mail";
import Calendar from "@/components/blocks/Calendar";
const sendServerRequest = (type, payload) => {
const xhr = new XMLHttpRequest();
const url = "/persistence";
xhr.open("GET", url + "?type=" + type + "&" + payload);
xhr.send();
return xhr;
}
export default {
name: 'Home',
deleting: false,
......@@ -51,8 +61,11 @@ export default {
height: 300,
blocks: [{type: "Feed", width: 50}, {type: "Mail", width: 25}, {type: "Mail", width: 25}]
}
]
};
],
mouseDragPos: {x: 0, y: 0},
verticalResizeObject: {index: 0},
horizontalResizeObject: {row: 0, col: 0}
}
},
methods: {
......@@ -135,7 +148,101 @@ export default {
for (const pen of pens) {
pen.style.display = "block";
}
}
},
resizeHorizontalMouseMove(event) {
const deltaX = this.mouseDragPos.x - event.x;
this.mouseDragPos.x = event.x;
const row = this.horizontalResizeObject.row;
const col = this.horizontalResizeObject.col;
// Find index of select col in html document
let colIndex = col;
for (let i = 0; i < row; i++) {
const element = this.layout[i];
colIndex += element.blocks.length;
}
const leftCol = document.getElementsByClassName("col")[colIndex - 1];
const rigthCol = document.getElementsByClassName("col")[colIndex];
// Total flex allowed from layout
const totalFlex = this.layout[row].blocks[col -1].width + this.layout[row].blocks[col].width;
const contentWidth = leftCol.clientWidth + rigthCol.clientWidth + 40;
// Resized size
const newLeftWidth = leftCol.clientWidth - deltaX;
const newRightWidth = rigthCol.clientWidth + deltaX;
// Calculating new flexGrow value
// This is not normalized to 100"%"
let newFlexRight = contentWidth/newRightWidth;
let newFlexLeft = (newLeftWidth * parseFloat(newFlexRight))/newRightWidth;
// Normalizing flewGrow to 100"%"
const preAdjustedTotalFlex = newFlexRight+newFlexLeft;
newFlexRight = (newFlexRight/preAdjustedTotalFlex)*totalFlex;
newFlexLeft = (newFlexLeft/preAdjustedTotalFlex)*totalFlex;
// Storing new style.
this.layout[row].blocks[col -1].width = newFlexLeft;
this.layout[row].blocks[col].width = newFlexRight;
},
resizeVerticalMouseMove(event){
const deltaY = this.mouseDragPos.y - event.y;
this.mouseDragPos.y = event.y;
this.layout[this.verticalResizeObject.index].height -= deltaY
},
resizeHorizontal(event, row, col){