Compare commits

...

10 Commits

Author SHA1 Message Date
9671be1ff3 Updating references to old api/ to clippable-svc/ 2022-10-28 12:12:21 -07:00
348410853a Renamed api to clippable-svc to be more clear 2022-10-28 12:09:29 -07:00
54af3628e4 - Removing out of scope code 2022-05-04 17:46:22 -07:00
dc98feef5f + Required job dependencies for cargo builders
'needs' keyword also added for meme graph lines
2022-03-27 00:49:36 -07:00
ba0d75d383 + New jobs for building both admin and normal docker images
+ New jobs for building both admin and normal binary packages

! NOTE: This commit is likely broken so do not use it to checkout
2022-03-27 00:45:07 -07:00
9f78f316c5 +* Ansible role meta data 2022-03-27 00:43:14 -07:00
988d598a19 + Base job for deploy docker images to gitlab repos 2022-03-27 00:42:47 -07:00
1fd47481c8 + Base job for building cargo binaries
script field is the only that "userland" code needs to
override
2022-03-27 00:41:47 -07:00
4416d08994 + admin::populate_video_list now populates t he video list
The ul here is meant to serve as a quick
way to check what videos are being served
as well as removing videos

+ category::VideoMeta::as_li built for admin video list
This is basically how we spit this out onto
the DOM
2022-03-27 00:00:50 -07:00
d1e2d80eae + Font awesome images
+ Styling for admin video list
2022-03-26 23:58:53 -07:00
52 changed files with 172 additions and 457 deletions

15
.gitignore vendored
View File

@ -3,13 +3,13 @@ msg
tmp/
keys/
api/target/
api/dev/
api/vids/
api/static/js/
api/static/dist/
api/thumbs/
api/*.db
clippable-svc/target/
clippable-svc/dev/
clippable-svc/vids/
clippable-svc/static/js/
clippable-svc/static/dist/
clippable-svc/thumbs/
clippable-svc/*.db
build/
gitpage/public/
@ -29,3 +29,4 @@ ts/dist/
ts/node_modules/
.vscode/settings.json
api/.vscode/settings.json
api/.ycm_extra_conf.py

View File

@ -4,6 +4,10 @@ stages:
- build-backend
- deploy
include:
- local: 'ci/cargo.yml'
- local: 'ci/docker.yml'
pages:
image: shockrah/website:latest
stage: pages
@ -22,62 +26,67 @@ pages:
paths:
- public/
# Webpack bundles everything anyway so both admin/non-admin builds have
# the same frontend code.
build-frontend-js:
image: codesignal/typescript:v9.6.0
stage: build-frontend
stage: pages
only:
refs:
- master
script:
- cd ts/
- npm run setup
- npm i
- npm run build
artifacts:
paths:
- api/static/
- clippable-svc/static/
# Literally both of these fail 99% of the time so I'm forgoing them completely
# for now until I find something doesn't suck
# Builds out the intended zip package
build-server-binaries:
image: rustlang/rust:nightly
build-server-no-admin:
extends: .cargo-builder
stage: build-backend
stage: pages
only:
refs:
- master
needs:
- build-frontend-js
dependencies:
- build-frontend-js
script:
- mkdir -p build
- cp api/templates/ api/static/ build/ -r
- cd api/
- cd clippable-svc/
- cargo build --release
- cd ../
- cp api/target/release/clippable-server build/server
- cp ./scripts/ build/ -r
- cp readme.md build/
- sh ./scripts/default-rocket-toml.sh
artifacts:
paths:
- build/
# Upload built docker image to the local registry
deploy-docker-image:
stage: deploy
image: docker:stable
only:
refs:
- master
build-server-admin-enabled:
extends: .cargo-builder
stage: build-backend
needs:
- build-server-binaries
- build-frontend-js
dependencies:
- build-server-binaries
services:
- docker:dind
- build-frontend-js
script:
- cd clippable-svc/
- cargo build --release --features admin
- cd ../
deploy-no-admin-docker:
stage: deploy
extends: .docker-deploy
needs:
- build-server-no-admin
dependencies:
- build-server-no-admin
script:
- echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY"
- docker build -t registry.gitlab.com/shockrah/clippable .
- docker push registry.gitlab.com/shockrah/clippable
deploy-admin-docker:
stage: deploy
extends: .docker-deploy
needs:
- build-server-admin-enabled
dependencies:
- build-server-admin-enabled
script:
- docker build -t registry.gitlab.com/shockrah/clippable:admin .
- docker push registry.gitlab.com/shockrah/clippable:admin

View File

@ -1,14 +0,0 @@
resource "aws_ebs_volume" "app_volume" {
availability_zone = var.availability_zone
size = 20
type = "standard"
tags = {
Name = "APP Video block storage"
}
}
resource "aws_volume_attachment" "ebs_att" {
device_name = "/dev/sdf"
volume_id = aws_ebs_volume.app_volume.id
instance_id = aws_instance.app_instance.id
}

View File

@ -1,35 +0,0 @@
# This here module takes care of setting up the ec2 instances that our
# containers will bind to later on
variable "aws_key" {}
variable "aws_secret" {}
variable "aws_region" {}
variable "ami_id" {}
variable "instance_type" {}
variable "ssh_key_name" {}
variable "public_key_path" {}
variable "availability_zone" {}
provider "aws" {
access_key = var.aws_key
secret_key = var.aws_secret
region = var.aws_region
max_retries = 1
}
resource "aws_key_pair" "sshkey" {
key_name = var.ssh_key_name
public_key = file(var.public_key_path)
}
resource "aws_instance" "app_instance" {
ami = var.ami_id
instance_type = var.instance_type
key_name = var.ssh_key_name
security_groups = [ aws_security_group.app_security_group.id ]
subnet_id = aws_subnet.app_public_subnet.id
tags = {
Name = "Clippable App Instance"
}
}

View File

@ -1,7 +0,0 @@
resource "aws_eip" "app_eip" {
instance = aws_instance.app_instance.id
vpc = true
tags = {
Name = "Clippable EIP"
}
}

View File

@ -1,6 +0,0 @@
resource "aws_internet_gateway" "app_gateway" {
vpc_id = aws_vpc.app_vpc.id
tags = {
Name = "Clippable app internet gateway"
}
}

View File

@ -1,12 +0,0 @@
resource "aws_route_table" "app_route_table" {
vpc_id = aws_vpc.app_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.app_gateway.id
}
}
resource "aws_route_table_association" "app_subnet_assoc" {
subnet_id = aws_subnet.app_public_subnet.id
route_table_id = aws_route_table.app_route_table.id
}

View File

@ -1,32 +0,0 @@
#!/bin/sh
# This script runs in order to to set things up for so that we don't have to do
# much else by ourselves
# No harm in using sudo even as root its just a little pointless
# Doing this with our ami however means we don't have to check if we're root
# for privileged operations at provision-time
apt="sudo apt"
server_name=$1
if [ -z "$server_name" ];then
echo A servername must be given as an argument
fi
$apt update
$apt upgrade
$apt install -y nginx certbot
sudo mkdir -p /var/www/clippable
# Creating the reverse proxy configuration for nginx
# WARN: Also we're assuming that the webserver has the default port
# Only this because certbot does the rest
cat << EOF > /etc/nginx/sites-available/clippable
server {
server_name $server_name;
location / {
proxy_pass http://0.0.0.0:8482;
};
}
EOF

View File

@ -1,39 +0,0 @@
resource "aws_security_group" "app_security_group" {
name = "App sec group"
description = "Allowing SSH and web traffic"
vpc_id = aws_vpc.app_vpc.id
ingress {
cidr_blocks = ["0.0.0.0/0"]
from_port = 443
to_port = 443
protocol = "tcp"
}
ingress {
cidr_blocks = ["0.0.0.0/0"]
from_port = 80
to_port = 80
protocol = "tcp"
}
ingress {
cidr_blocks = ["0.0.0.0/0"]
from_port = 22
to_port = 22
protocol = "tcp"
}
# These are so that we can update the system regularly using apt and sometimes
# with tarballs if we're updating something from source
egress {
cidr_blocks = ["0.0.0.0/0"]
from_port = 443
to_port = 443
protocol = "tcp"
}
egress {
cidr_blocks = ["0.0.0.0/0"]
from_port = 80
to_port = 80
protocol = "tcp"
}
}

View File

@ -1,5 +0,0 @@
resource "aws_subnet" "app_public_subnet" {
vpc_id = aws_vpc.app_vpc.id
cidr_block = "10.0.0.128/26"
availability_zone = var.availability_zone
}

View File

@ -1,10 +0,0 @@
resource "aws_vpc" "app_vpc" {
cidr_block = "10.0.0.128/26"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "Clippable APP VPC"
}
}

View File

@ -1,57 +0,0 @@
Role Name
=========
This role is dedicated to making the setup and administration of a clippable
server a little bit easier for those intending on running their own instance.
There are playbooks for maintaining this service both as a container and as a
service running on System D.
Role Variables
--------------
Vars in: `defaults/main.yml`
* `remote_user`: Default username to use for regular tasks
Set to `admin` by default.
* `remote_app_dir`: Directory to install application files into
Set to `/home/{{remote_user}}/app` by default
This includes things like the server binary and HTML template files.
You only need to worry about this if you're not going to run this
in a container.
* `main_host`
Set to `main` by default.
Host that you intend on targeting.
Dependencies
------------
* community.docker
This is only required if you are planning on using any of the docker playbooks.
Example Playbook
----------------
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
License
-------
GPL V3
Author Information
------------------
Author: Shockrah
Email: dev@shockrah.xyz

View File

@ -1,4 +0,0 @@
---
remote_user: admin
remote_app_dir: "/home/{{remote_user}}/app"
main_host: main

View File

@ -1,2 +0,0 @@
---
# handlers file for playbooks

View File

@ -1,52 +0,0 @@
galaxy_info:
author: your name
description: your role description
company: your company (optional)
# If the issue tracker for your role is not on github, uncomment the
# next line and provide a value
# issue_tracker_url: http://example.com/issue/tracker
# Choose a valid license ID from https://spdx.org - some suggested licenses:
# - BSD-3-Clause (default)
# - MIT
# - GPL-2.0-or-later
# - GPL-3.0-only
# - Apache-2.0
# - CC-BY-4.0
license: license (GPL-2.0-or-later, MIT, etc)
min_ansible_version: 2.1
# If this a Container Enabled role, provide the minimum Ansible Container version.
# min_ansible_container_version:
#
# Provide a list of supported platforms, and for each platform a list of versions.
# If you don't wish to enumerate all versions for a particular platform, use 'all'.
# To view available platforms and versions (or releases), visit:
# https://galaxy.ansible.com/api/v1/platforms/
#
# platforms:
# - name: Fedora
# versions:
# - all
# - 25
# - name: SomePlatform
# versions:
# - all
# - 1.0
# - 7
# - 99.99
galaxy_tags: []
# List tags for your role here, one per line. A tag is a keyword that describes
# and categorizes the role. Users find roles by searching for tags. Be sure to
# remove the '[]' above, if you add tags to this list.
#
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
# Maximum 20 tags per role.
dependencies: []
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
# if you add dependencies to this list.

View File

@ -1,41 +0,0 @@
---
tasks:
- name: Install docker dependencies
become: yes
become_method: sudo
apt:
name: "{{item}}"
update_cache: yes
loop:
- apt-transport-https
- ca-certificates
- curl
- gnupg
- software-properties-common
- lsb-release
- name: Install docker GPG key
become: yes
become_method: sudo
apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
state: present
- name: Add Docker Apt Repo
become: yes
become_method: sudo
apt_repository:
repo: deb https://download.docker.com/linux/ubuntu impish stable
state: present
- name: Install Docker components
become: yes
become_method: sudo
apt:
name: "{{item}}"
update_cache: yes
loop:
- docker-ce
- docker-ce-cli
- containerd.io

View File

@ -1,9 +0,0 @@
# This playbook is setup to install docker on debian based systems
---
- hosts: main
tasks:
- include_tasks: 'debian.yml'
when:
ansible_distribution: Debian

View File

@ -1,59 +0,0 @@
# WHEN TO USE THIS PLAYBOOK:
# Use this if you're running clippable under systemd
# WHAT THIS PLAYBOOK DOES:
# This playbooks basically takes a build/ directory similar to what the Gitlab
# pipelines generate and uploads those files to the desired directory
---
- hosts: {{ main_host }}
remote_user: {{ remote_user }}
tasks:
- name: Build skeleton root directory
file:
path: '{{remote_app_dir}}'
state: directory
- name: Build skeleton static directory
file:
path: '{{remote_app_dir}}/static'
state: directory
- name: Build skeleton css directory
file:
path: '{{remote_app_dir}}/static/css'
state: directory
- name: Build skeleton js directory
file:
path: '{{remote_app_dir}}/static/js'
state: directory
- name: Build skeleton templates directory
file:
path: '{{remote_app_dir}}/templates'
state: directory
- name: Update Binary installation
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
with_items:
- { src: ../../build/static/css/style.css, dest: '{{remote_app_dir}}/static/css/'}
- { src: ../../build/static/js/index.js, dest: '{{remote_app_dir}}/static/js/'}
- { src: ../../build/static/js/category.js, dest: '{{remote_app_dir}}/static//js/'}
- { src: ../../build/static/cantfindshit.jpg, dest: '{{remote_app_dir}}/static/'}
- { src: ../../build/static/favicon.png, dest: '{{remote_app_dir}}/static/'}
- { src: ../../build/templates/list.html.tera, dest: '{{remote_app_dir}}/templates/list.html.tera'}
- { src: ../../build/templates/video.html.tera, dest: '{{remote_app_dir}}/templates/video.html.tera'}
- { src: ../../build/Rocket.toml, dest: '{{remote_app_dir}}/'}
- { src: ../../build/server, dest: '{{remote_app_dir}}/'}
- name: Restart web service
become: yes
become_method: sudo
service:
name: app
state: restarted

View File

@ -1,2 +0,0 @@
localhost

View File

@ -1,5 +0,0 @@
---
- hosts: localhost
remote_user: root
roles:
- playbooks

View File

@ -1,2 +0,0 @@
---
# vars file for playbooks

View File

@ -1,8 +0,0 @@
# AWS Configuration
For those that would like to deploy a minimal instance to AWS via terraform
this directory will basically have everything you need to get a working instance
up and running for very cheap with an EC2 instance.
There is still the question of preparing the EC2 instance itself however the
amount of configuration is very light.

View File

@ -1,5 +0,0 @@
# NOTE: sample inventory either use your own inventory file or just
# replace the hostname/ip below
[main]
1.1.1.1

16
ci/cargo.yml Normal file
View File

@ -0,0 +1,16 @@
.cargo-builder:
image: rustlang/rust:nightly
only:
refs:
- master
before_script:
- mkdir -p build
- cp clippable-svc/templates/ clippable-svc/static/ build/ -r
after_script:
- cp clippable-svc/target/release/clippable-server build/server
- cp ./scripts/ build/ -r
- cp readme.md build/
- sh ./scripts/default-rocket-toml.sh
artifacts:
paths:
- build/

9
ci/docker.yml Normal file
View File

@ -0,0 +1,9 @@
.docker-deploy:
image: docker:stable
services:
- docker:dind
only:
refs:
- master
before_script:
- echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY"

3
clippable-svc/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"rust.all_features": true
}

View File

@ -0,0 +1,9 @@
def Settings(**kwargs):
return {
'ls': {
'cargo': {
'features': ['admin'],
'noDefaultFeatures': True
}
}
}

View File

@ -56,6 +56,8 @@ pub fn get_category_thumbnail(category: &str) -> std::io::Result<String> {
})
}
/// Returns a List of categories
/// Primarily used on the main page
/// WARN: misconfigured servers are just going to get shafted and serve up
/// a tonne of 500's
#[get("/categories")]

View File

@ -83,3 +83,18 @@ video {
#video-meta {
text-align: left;
}
.admin-video-li {
color: black;
text-shadow: none;
padding-right: 1em;
}
.admin-video-li:hover {
color: #0a58ca;
text-shadow: none;
}
.align-left {
text-align: left;
}

View File

@ -4,6 +4,8 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p" crossorigin="anonymous"/>
<link rel="stylesheet" type="text/css" href="/static/css/style.css">
<title>Clippable Admin Dashboard</title>
<link rel="shortcut icon" type="image/png" href="/static/favicon.png"/>
@ -60,6 +62,10 @@
<button type="button" class="btn btn-primary" id="confirm-upload-btn">Upload</button>
</div>
<div id="upload-response"></div>
<div class="vids-meta-list">
<h1>Videos</h1>
<ul class="list-group" id="videos-list"></ul>
</div>
</div>
</div>
</div>

View File

@ -10,9 +10,9 @@ cargo build --release
mkdir -p build/
cp target/release/api build/server
cp api/templates/ build/ -r
cp api/static/ build -r
cp target/release/clippable-svc build/server
cp clippable-svc/templates/ build/ -r
cp clippable-svc/static/ build -r
bash ./scripts/default-rocket-toml.sh
docker build -t registry.gitlab.com/shockrah/clippable .

View File

@ -1,8 +1,8 @@
// This module serves as convenience for admin users to upload/remove videos
// from their clippable instance. There are no fancy tricks as this is meant
// purely to be a UX thing.
//import { fetch_category_videos } from './category'
//import { fetch_categories } from './index'
import { fetch_category_videos, VideoMeta } from './category'
import { fetch_categories } from './index'
let UID: null|string = null
@ -79,7 +79,6 @@ export function populate_meta_form() {
let file = document.getElementById('video-file') as HTMLInputElement
// When we remove the file this array becomes 0 so the check is required
console.log('files found', file.files.length)
if(file.files.length == 0) {
document.getElementById('video-meta').hidden = true
} else {
@ -93,6 +92,24 @@ export function populate_meta_form() {
}
}
async function populate_video_list() {
const categories = await fetch_categories()
let videos: Array<VideoMeta> = []
for(const cat of categories) {
const vids = await fetch_category_videos(cat.name)
for(const v of vids) {
videos.push(v)
}
}
const list_ref = document.getElementById("videos-list")
for(const video of videos) {
list_ref.appendChild(video.as_li())
}
}
document.addEventListener('DOMContentLoaded', () => {
/*
* Setting up hooks required for functionality
@ -100,4 +117,7 @@ document.addEventListener('DOMContentLoaded', () => {
document.getElementById('video-file').onchange = populate_meta_form
document.getElementById('verify-login-btn').onclick = confirm_auth
document.getElementById('confirm-upload-btn').onclick = upload_video
populate_video_list()
.then(value => console.log('succesful list population: ', value))
.catch(reason => console.log('Failure in populate_video_list', reason))
})

View File

@ -1,8 +1,9 @@
class VideoMeta {
export class VideoMeta {
name: string|null
thumbnail: string|null
category: string
basename: string|null
href: string
constructor(raw: any) {
this.name = raw['name']
@ -14,6 +15,8 @@ class VideoMeta {
this.basename = this.name ?
this.name.slice(0, this.name.lastIndexOf('.')) :
null
this.href = `/clip/${this.category}/${this.basename}`
}
private clean_link(link: string) : string {
@ -28,7 +31,7 @@ class VideoMeta {
let container = document.createElement('h2')
let link = document.createElement('a')
if(this.name) {
link.href = `/clip/${this.category}/${this.basename}`
link.href = this.href
link.text = this.clean_link(this.name)
} else {
link.href = '#'
@ -77,10 +80,38 @@ class VideoMeta {
return container
}
public as_li() : HTMLElement {
const li = document.createElement('li')
li.className = 'align-left list-group-item'
const link = document.createElement('a')
link.href = `/clip/${this.category}/${this.name}`
link.target = '_blank'
link.textContent = this.name
link.className = 'admin-video-li btn'
li.appendChild(link)
const thumbnail_link = document.createElement('a')
thumbnail_link.href = `/thumbnail/${this.category}/${this.name}.jpg`
link.target = '_blank'
thumbnail_link.innerHTML = '<i class="fa-solid fa-image"></i>'
thumbnail_link.className = 'admin-video-li btn'
li.appendChild(thumbnail_link)
const delete_btn = document.createElement('button')
delete_btn.type = 'button'
delete_btn.className = 'btn btn-danger'
delete_btn.innerHTML = '<i class="fa-solid fa-trash"></i>'
li.appendChild(delete_btn)
return li
}
}
export async function fetch_category_videos() : Promise<Array<VideoMeta>> {
const endpoint = window.location.origin + '/api' + window.location.pathname
export async function fetch_category_videos(name?: string) : Promise<Array<VideoMeta>> {
const category = name ? name : window.location.pathname
const endpoint = window.location.origin + `/api/category/${category}`
let videos: Array<VideoMeta> = []
const response = await fetch(endpoint)
if(response.headers.get('Content-Type') == 'application/json') {