mirror of
https://github.com/mainnika/nikita-tokarch-uk.git
synced 2026-05-25 01:03:35 +00:00
Merge branch 'main' into develop
This commit is contained in:
+2
-1
@@ -1,6 +1,7 @@
|
||||
*
|
||||
!cmd
|
||||
!nginx
|
||||
!frontend
|
||||
!pkg
|
||||
!web
|
||||
!go.mod
|
||||
!go.sum
|
||||
|
||||
@@ -3,7 +3,9 @@ name: Docker
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ main ]
|
||||
branches:
|
||||
- 'main'
|
||||
- 'develop'
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
@@ -22,6 +24,11 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.8'
|
||||
|
||||
- name: Install cosign
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: sigstore/cosign-installer@main
|
||||
@@ -37,17 +44,38 @@ jobs:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get date as semver
|
||||
id: calver
|
||||
env:
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
run: |
|
||||
python -c "
|
||||
from datetime import datetime, timedelta
|
||||
from os import environ
|
||||
ref = environ['REF_NAME']
|
||||
now = datetime.now()
|
||||
date = now.strftime('%y.%m.%d')
|
||||
delta = timedelta(hours=now.hour,minutes=now.minute,seconds=now.second)
|
||||
print(f'::set-output name=current::{date}-{ref}.{delta.seconds}')
|
||||
"
|
||||
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=raw,value=${{ steps.calver.outputs.current }}
|
||||
type=raw,value=${{ github.ref_name }}
|
||||
type=sha
|
||||
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
build-args: |
|
||||
APP_VERSION=${{ steps.calver.outputs.current }}
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
+3
-2
@@ -16,13 +16,14 @@ RUN --mount=type=cache,id=gopath,target=${GOPATH} \
|
||||
|
||||
ARG APP_VERSION=containerized
|
||||
|
||||
COPY frontend frontend
|
||||
COPY cmd cmd
|
||||
COPY pkg pkg
|
||||
|
||||
RUN --mount=type=cache,id=gopath,target=${GOPATH} \
|
||||
go build \
|
||||
-o nikita-tokarch-uk-frontend \
|
||||
-ldflags "-X main.Version=${APP_VERSION}" \
|
||||
code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend
|
||||
code.tokarch.uk/mainnika/nikita-tokarch-uk/cmd/renderer
|
||||
|
||||
FROM registry.access.redhat.com/ubi8/ubi as js-builder
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*.orig
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
||||
@@ -0,0 +1,6 @@
|
||||
apiVersion: v2
|
||||
name: nikita-tokarch-uk
|
||||
description: A Helm chart for Kubernetes
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: main
|
||||
@@ -0,0 +1,22 @@
|
||||
1. Get the application URL by running these commands:
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- range $host := .Values.ingress.hosts }}
|
||||
{{- range .paths }}
|
||||
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- else if contains "NodePort" .Values.service.type }}
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "nikita-tokarch-uk.fullname" . }})
|
||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
echo http://$NODE_IP:$NODE_PORT
|
||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "nikita-tokarch-uk.fullname" . }}'
|
||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "nikita-tokarch-uk.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
|
||||
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "nikita-tokarch-uk.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
|
||||
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
|
||||
{{- end }}
|
||||
@@ -0,0 +1,62 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "nikita-tokarch-uk.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "nikita-tokarch-uk.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "nikita-tokarch-uk.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "nikita-tokarch-uk.labels" -}}
|
||||
helm.sh/chart: {{ include "nikita-tokarch-uk.chart" . }}
|
||||
{{ include "nikita-tokarch-uk.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "nikita-tokarch-uk.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "nikita-tokarch-uk.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "nikita-tokarch-uk.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
{{- default (include "nikita-tokarch-uk.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,10 @@
|
||||
{{- if .Values.config -}}
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: "{{ include "nikita-tokarch-uk.fullname" . }}-config"
|
||||
labels:
|
||||
{{- include "nikita-tokarch-uk.labels" . | nindent 4 }}
|
||||
data:
|
||||
{{- toYaml .Values.config | nindent 2 }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,84 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "nikita-tokarch-uk.fullname" . }}
|
||||
labels:
|
||||
{{- include "nikita-tokarch-uk.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "nikita-tokarch-uk.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/config: {{ include ( print $.Template.BasePath "/config.yaml" ) . | sha256sum }}
|
||||
{{- with .Values.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "nikita-tokarch-uk.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "nikita-tokarch-uk.serviceAccountName" . }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
command:
|
||||
- /usr/sbin/nginx
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 80
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /version.html
|
||||
port: http
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /version.html
|
||||
port: http
|
||||
resources:
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
- name: {{ .Chart.Name }}-renderer
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
workingDir: /etc/nikita-tokarch-uk
|
||||
command:
|
||||
- /usr/local/bin/nikita-tokarch-uk-frontend
|
||||
resources:
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: "{{ include "nikita-tokarch-uk.fullname" . }}-config"
|
||||
mountPath: /etc/nikita-tokarch-uk
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: "{{ template "nikita-tokarch-uk.fullname" . }}-config"
|
||||
{{- if .Values.config }}
|
||||
configMap:
|
||||
name: "{{ include "nikita-tokarch-uk.fullname" . }}-config"
|
||||
{{- else }}
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,61 @@
|
||||
{{- if .Values.ingress.enabled -}}
|
||||
{{- $fullName := include "nikita-tokarch-uk.fullname" . -}}
|
||||
{{- $svcPort := .Values.service.port -}}
|
||||
{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
|
||||
{{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }}
|
||||
{{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||
apiVersion: networking.k8s.io/v1beta1
|
||||
{{- else -}}
|
||||
apiVersion: extensions/v1beta1
|
||||
{{- end }}
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
labels:
|
||||
{{- include "nikita-tokarch-uk.labels" . | nindent 4 }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
|
||||
ingressClassName: {{ .Values.ingress.className }}
|
||||
{{- end }}
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ .path }}
|
||||
{{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
|
||||
pathType: {{ .pathType }}
|
||||
{{- end }}
|
||||
backend:
|
||||
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
|
||||
service:
|
||||
name: {{ $fullName }}
|
||||
port:
|
||||
number: {{ $svcPort }}
|
||||
{{- else }}
|
||||
serviceName: {{ $fullName }}
|
||||
servicePort: {{ $svcPort }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "nikita-tokarch-uk.fullname" . }}
|
||||
labels:
|
||||
{{- include "nikita-tokarch-uk.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
{{- include "nikita-tokarch-uk.selectorLabels" . | nindent 4 }}
|
||||
@@ -0,0 +1,12 @@
|
||||
{{- if .Values.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "nikita-tokarch-uk.serviceAccountName" . }}
|
||||
labels:
|
||||
{{- include "nikita-tokarch-uk.labels" . | nindent 4 }}
|
||||
{{- with .Values.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: "{{ include "nikita-tokarch-uk.fullname" . }}-test-connection"
|
||||
labels:
|
||||
{{- include "nikita-tokarch-uk.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
"helm.sh/hook": test
|
||||
spec:
|
||||
containers:
|
||||
- name: wget
|
||||
image: busybox
|
||||
command: ['wget']
|
||||
args: ['{{ include "nikita-tokarch-uk.fullname" . }}:{{ .Values.service.port }}']
|
||||
restartPolicy: Never
|
||||
@@ -0,0 +1,77 @@
|
||||
# Default values for nikita-tokarch-uk.
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
|
||||
# config:
|
||||
# frontend.yaml: |-
|
||||
|
||||
replicaCount: 1
|
||||
|
||||
image:
|
||||
repository: ghcr.io/mainnika/nikita-tokarch-uk
|
||||
pullPolicy: Always
|
||||
# tag: "main"
|
||||
|
||||
imagePullSecrets: []
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
|
||||
serviceAccount:
|
||||
# Specifies whether a service account should be created
|
||||
create: false
|
||||
# Annotations to add to the service account
|
||||
annotations: {}
|
||||
# The name of the service account to use.
|
||||
# If not set and create is true, a name is generated using the fullname template
|
||||
name: ""
|
||||
|
||||
podAnnotations: {}
|
||||
|
||||
podSecurityContext: {}
|
||||
# fsGroup: 2000
|
||||
|
||||
securityContext: {}
|
||||
# capabilities:
|
||||
# drop:
|
||||
# - ALL
|
||||
# readOnlyRootFilesystem: true
|
||||
# runAsNonRoot: true
|
||||
# runAsUser: 1000
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 80
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
className: "nginx"
|
||||
annotations: {}
|
||||
# kubernetes.io/ingress.class: nginx
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
hosts:
|
||||
- host: nikita.tokarch.uk
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls: []
|
||||
# - secretName: chart-example-tls
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
|
||||
resources: {}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
||||
@@ -9,11 +9,10 @@ import (
|
||||
"github.com/spf13/viper"
|
||||
"github.com/valyala/fasthttp"
|
||||
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/config"
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/ghost"
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/renderer"
|
||||
|
||||
_ "code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/templates"
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/config"
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost/v4api/httpclient"
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/routes"
|
||||
_ "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/templates"
|
||||
)
|
||||
|
||||
var Version = "nightly"
|
||||
@@ -53,14 +52,15 @@ func main() {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
ghostClient := &ghost.HTTPClient{
|
||||
Addr: config.Content.Backend,
|
||||
ghostClient := &httpclient.HTTPClient{
|
||||
Addr: config.Content.Backend.Addr,
|
||||
Secured: config.Content.Backend.Secured,
|
||||
Headers: config.Content.Backend.Headers,
|
||||
ContentKey: config.Content.Key,
|
||||
Secured: true,
|
||||
QueryTimeout: time.Second,
|
||||
}
|
||||
|
||||
rendererHandler := &renderer.Renderer{
|
||||
apiRoutes := &routes.Routes{
|
||||
GhostClient: ghostClient,
|
||||
ContentConfig: config.Content,
|
||||
Base: config.Base,
|
||||
@@ -68,7 +68,7 @@ func main() {
|
||||
|
||||
httpServer := fasthttp.Server{
|
||||
Logger: logrus.StandardLogger(),
|
||||
Handler: rendererHandler.Handler,
|
||||
Handler: apiRoutes.Handler,
|
||||
Name: frontendServerIdentity,
|
||||
GetOnly: true,
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package ghost
|
||||
|
||||
//go:generate $GOPATH/bin/easyjson -pkg -no_std_marshalers
|
||||
|
||||
// Client is the ghost backend client
|
||||
type Client interface {
|
||||
GetPosts(params ...QueryParam) (posts *Posts, err error)
|
||||
GetPostBySlug(slug string, params ...QueryParam) (posts *Posts, err error)
|
||||
GetPageBySlug(slug string) (pages *Pages, err error)
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package ghost
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
// QueryParam is the generic query param applier
|
||||
type QueryParam interface {
|
||||
Apply(headers *fasthttp.RequestHeader, args *fasthttp.Args)
|
||||
}
|
||||
|
||||
// QueryLimit returns limit param query
|
||||
func QueryLimit(limit int) queryLimit {
|
||||
return queryLimit{limit: limit}
|
||||
}
|
||||
|
||||
// QueryPage returns page param query
|
||||
func QueryPage(page int) queryPage {
|
||||
return queryPage{page: page}
|
||||
}
|
||||
|
||||
// queryLimit implements the limit param query applier
|
||||
type queryLimit struct{ limit int }
|
||||
|
||||
// Apply applies the limit argument to the query
|
||||
func (ql queryLimit) Apply(headers *fasthttp.RequestHeader, args *fasthttp.Args) {
|
||||
|
||||
if ql.limit == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
args.Add("limit", strconv.Itoa(ql.limit))
|
||||
}
|
||||
|
||||
// queryPage implements the page param query applier
|
||||
type queryPage struct{ page int }
|
||||
|
||||
// Apply applies the page argument to the query
|
||||
func (qp queryPage) Apply(headers *fasthttp.RequestHeader, args *fasthttp.Args) {
|
||||
|
||||
if qp.page < 2 {
|
||||
return
|
||||
}
|
||||
|
||||
args.Add("page", strconv.Itoa(qp.page))
|
||||
}
|
||||
@@ -38,6 +38,10 @@ http {
|
||||
try_files $uri $uri/ @frontend;
|
||||
}
|
||||
|
||||
location = / {
|
||||
proxy_pass http://frontend;
|
||||
}
|
||||
|
||||
location @frontend {
|
||||
proxy_pass http://frontend;
|
||||
}
|
||||
|
||||
@@ -8,12 +8,19 @@ import (
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// Backend contains backend connection-specific configuration
|
||||
type Backend struct {
|
||||
Addr string `mapstructure:"addr"`
|
||||
Secured bool `mapstructure:"secured"`
|
||||
Headers map[string]string `mapstructure:"headers"`
|
||||
}
|
||||
|
||||
// Content contains content-specific configuration
|
||||
type Content struct {
|
||||
Backend string `mapstructure:"backend"`
|
||||
Key string `mapstructure:"key"`
|
||||
Pinned string `mapstructure:"pinned"`
|
||||
PostsPerPage int `mapstructure:"postsPerPage"`
|
||||
Backend Backend `mapstructure:"backend"`
|
||||
Key string `mapstructure:"key"`
|
||||
Pinned string `mapstructure:"pinned"`
|
||||
PostsPerPage int `mapstructure:"postsPerPage"`
|
||||
}
|
||||
|
||||
// Config contains application configuration
|
||||
@@ -36,7 +43,9 @@ func init() {
|
||||
pflag.String("unix", "", "unix socket path to listen")
|
||||
pflag.String("base", "", "http URI prefix")
|
||||
|
||||
pflag.String("content.backend", "demo.ghost.io:443", "ghost backend addr")
|
||||
pflag.StringToString("content.backend.headers", nil, "map of additional headers to send")
|
||||
pflag.String("content.backend.addr", "demo.ghost.io:443", "ghost backend addr")
|
||||
pflag.Bool("content.backend.secured", true, "is ghost backend secured")
|
||||
pflag.String("content.key", "22444f78447824223cefc48062", "ghost content api key")
|
||||
pflag.String("content.pinned", "contact", "pinned page slug")
|
||||
pflag.Int("content.postsPerPage", 5, "amount of posts per page")
|
||||
@@ -3,15 +3,15 @@ package content
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/ghost"
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost/data"
|
||||
)
|
||||
|
||||
// Blog content data
|
||||
type Blog struct {
|
||||
_ interface{} `template:"blog.go.tmpl"`
|
||||
ghost.Meta
|
||||
Pinned []ghost.Post
|
||||
Posts []ghost.Post
|
||||
data.Meta
|
||||
Pinned []data.Post
|
||||
Posts []data.Post
|
||||
}
|
||||
|
||||
// Title returns blog content title
|
||||
@@ -1,15 +1,13 @@
|
||||
package content
|
||||
|
||||
import (
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/ghost"
|
||||
)
|
||||
import "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost/data"
|
||||
|
||||
// Index content data
|
||||
type Index struct {
|
||||
_ interface{} `template:"index.go.tmpl"`
|
||||
ghost.Meta
|
||||
Pinned []ghost.Post
|
||||
Posts []ghost.Post
|
||||
data.Meta
|
||||
Pinned []data.Post
|
||||
Posts []data.Post
|
||||
}
|
||||
|
||||
// Title returns index title
|
||||
@@ -1,4 +1,6 @@
|
||||
package ghost
|
||||
package data
|
||||
|
||||
//go:generate $GOPATH/bin/easyjson -pkg -no_std_marshalers
|
||||
|
||||
import "html/template"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
|
||||
|
||||
package ghost
|
||||
package data
|
||||
|
||||
import (
|
||||
json "encoding/json"
|
||||
@@ -18,7 +18,7 @@ var (
|
||||
_ easyjson.Marshaler
|
||||
)
|
||||
|
||||
func easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost(in *jlexer.Lexer, out *Posts) {
|
||||
func easyjson794297d0DecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData(in *jlexer.Lexer, out *Posts) {
|
||||
isTopLevel := in.IsStart()
|
||||
if in.IsNull() {
|
||||
if isTopLevel {
|
||||
@@ -72,7 +72,7 @@ func easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost(in
|
||||
in.Consumed()
|
||||
}
|
||||
}
|
||||
func easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost(out *jwriter.Writer, in Posts) {
|
||||
func easyjson794297d0EncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData(out *jwriter.Writer, in Posts) {
|
||||
out.RawByte('{')
|
||||
first := true
|
||||
_ = first
|
||||
@@ -102,14 +102,14 @@ func easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost(out
|
||||
|
||||
// MarshalEasyJSON supports easyjson.Marshaler interface
|
||||
func (v Posts) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost(w, v)
|
||||
easyjson794297d0EncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData(w, v)
|
||||
}
|
||||
|
||||
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
|
||||
func (v *Posts) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||
easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost(l, v)
|
||||
easyjson794297d0DecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData(l, v)
|
||||
}
|
||||
func easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost1(in *jlexer.Lexer, out *Post) {
|
||||
func easyjson794297d0DecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData1(in *jlexer.Lexer, out *Post) {
|
||||
isTopLevel := in.IsStart()
|
||||
if in.IsNull() {
|
||||
if isTopLevel {
|
||||
@@ -148,7 +148,7 @@ func easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost1(in
|
||||
in.Consumed()
|
||||
}
|
||||
}
|
||||
func easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost1(out *jwriter.Writer, in Post) {
|
||||
func easyjson794297d0EncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData1(out *jwriter.Writer, in Post) {
|
||||
out.RawByte('{')
|
||||
first := true
|
||||
_ = first
|
||||
@@ -182,14 +182,14 @@ func easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost1(ou
|
||||
|
||||
// MarshalEasyJSON supports easyjson.Marshaler interface
|
||||
func (v Post) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost1(w, v)
|
||||
easyjson794297d0EncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData1(w, v)
|
||||
}
|
||||
|
||||
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
|
||||
func (v *Post) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||
easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost1(l, v)
|
||||
easyjson794297d0DecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData1(l, v)
|
||||
}
|
||||
func easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost2(in *jlexer.Lexer, out *Pagination) {
|
||||
func easyjson794297d0DecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData2(in *jlexer.Lexer, out *Pagination) {
|
||||
isTopLevel := in.IsStart()
|
||||
if in.IsNull() {
|
||||
if isTopLevel {
|
||||
@@ -226,7 +226,7 @@ func easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost2(in
|
||||
in.Consumed()
|
||||
}
|
||||
}
|
||||
func easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost2(out *jwriter.Writer, in Pagination) {
|
||||
func easyjson794297d0EncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData2(out *jwriter.Writer, in Pagination) {
|
||||
out.RawByte('{')
|
||||
first := true
|
||||
_ = first
|
||||
@@ -255,14 +255,14 @@ func easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost2(ou
|
||||
|
||||
// MarshalEasyJSON supports easyjson.Marshaler interface
|
||||
func (v Pagination) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost2(w, v)
|
||||
easyjson794297d0EncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData2(w, v)
|
||||
}
|
||||
|
||||
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
|
||||
func (v *Pagination) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||
easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost2(l, v)
|
||||
easyjson794297d0DecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData2(l, v)
|
||||
}
|
||||
func easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost3(in *jlexer.Lexer, out *Pages) {
|
||||
func easyjson794297d0DecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData3(in *jlexer.Lexer, out *Pages) {
|
||||
isTopLevel := in.IsStart()
|
||||
if in.IsNull() {
|
||||
if isTopLevel {
|
||||
@@ -316,7 +316,7 @@ func easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost3(in
|
||||
in.Consumed()
|
||||
}
|
||||
}
|
||||
func easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost3(out *jwriter.Writer, in Pages) {
|
||||
func easyjson794297d0EncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData3(out *jwriter.Writer, in Pages) {
|
||||
out.RawByte('{')
|
||||
first := true
|
||||
_ = first
|
||||
@@ -346,14 +346,14 @@ func easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost3(ou
|
||||
|
||||
// MarshalEasyJSON supports easyjson.Marshaler interface
|
||||
func (v Pages) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost3(w, v)
|
||||
easyjson794297d0EncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData3(w, v)
|
||||
}
|
||||
|
||||
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
|
||||
func (v *Pages) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||
easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost3(l, v)
|
||||
easyjson794297d0DecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData3(l, v)
|
||||
}
|
||||
func easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost4(in *jlexer.Lexer, out *Meta) {
|
||||
func easyjson794297d0DecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData4(in *jlexer.Lexer, out *Meta) {
|
||||
isTopLevel := in.IsStart()
|
||||
if in.IsNull() {
|
||||
if isTopLevel {
|
||||
@@ -384,7 +384,7 @@ func easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost4(in
|
||||
in.Consumed()
|
||||
}
|
||||
}
|
||||
func easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost4(out *jwriter.Writer, in Meta) {
|
||||
func easyjson794297d0EncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData4(out *jwriter.Writer, in Meta) {
|
||||
out.RawByte('{')
|
||||
first := true
|
||||
_ = first
|
||||
@@ -398,10 +398,10 @@ func easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost4(ou
|
||||
|
||||
// MarshalEasyJSON supports easyjson.Marshaler interface
|
||||
func (v Meta) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost4(w, v)
|
||||
easyjson794297d0EncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData4(w, v)
|
||||
}
|
||||
|
||||
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
|
||||
func (v *Meta) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||
easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost4(l, v)
|
||||
easyjson794297d0DecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData4(l, v)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package ghost
|
||||
|
||||
import (
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost/data"
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost/params"
|
||||
)
|
||||
|
||||
// Client is the ghost backend client
|
||||
type Client interface {
|
||||
// GetPosts returns blog posts according to query params
|
||||
GetPosts(queryParams ...params.Modifier) (posts *data.Posts, err error)
|
||||
// GetPostBySlug returns a single post by its slug title and query params
|
||||
GetPostBySlug(slug string, queryParams ...params.Modifier) (posts *data.Posts, err error)
|
||||
// GetPageBySlug returns a single page by its slug title and query params
|
||||
GetPageBySlug(slug string, queryParams ...params.Modifier) (pages *data.Pages, err error)
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package params
|
||||
|
||||
// Params are generics query argument
|
||||
type Params struct {
|
||||
Limit int
|
||||
Page int
|
||||
}
|
||||
|
||||
// Modifier function takes params and makes some changes
|
||||
type Modifier func(params Params) Params
|
||||
|
||||
// Modifiers is a list of modifier
|
||||
type Modifiers []Modifier
|
||||
|
||||
// Apply function modifies params
|
||||
func (ms Modifiers) Apply(params Params) Params {
|
||||
|
||||
for _, m := range ms {
|
||||
params = m(params)
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
// WithLimit modifier setups the limit
|
||||
func WithLimit(limit int) Modifier {
|
||||
return func(params Params) Params {
|
||||
params.Limit = limit
|
||||
return params
|
||||
}
|
||||
}
|
||||
|
||||
// WithPage modifier setups the page
|
||||
func WithPage(page int) Modifier {
|
||||
return func(params Params) Params {
|
||||
params.Page = page
|
||||
return params
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,20 @@
|
||||
package ghost
|
||||
package httpclient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/mailru/easyjson"
|
||||
"github.com/valyala/fasthttp"
|
||||
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost"
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost/data"
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost/params"
|
||||
)
|
||||
|
||||
var _ Client = (*HTTPClient)(nil)
|
||||
var _ ghost.Client = (*HTTPClient)(nil)
|
||||
|
||||
// Ghost content data URIs:
|
||||
const (
|
||||
@@ -25,6 +30,7 @@ type HTTPClient struct {
|
||||
ContentKey string
|
||||
Addr string
|
||||
Secured bool
|
||||
Headers map[string]string
|
||||
|
||||
client *fasthttp.HostClient
|
||||
|
||||
@@ -44,7 +50,7 @@ func (g *HTTPClient) setupClient() {
|
||||
}
|
||||
|
||||
// doQuery does the method and unmarshals the result into the easyjson Unmarshaler
|
||||
func (g *HTTPClient) doQuery(method string, v easyjson.Unmarshaler, params ...QueryParam) (err error) {
|
||||
func (g *HTTPClient) doQuery(path string, v easyjson.Unmarshaler, params params.Params) (err error) {
|
||||
|
||||
g.setupClientOnce.Do(g.setupClient)
|
||||
|
||||
@@ -55,17 +61,8 @@ func (g *HTTPClient) doQuery(method string, v easyjson.Unmarshaler, params ...Qu
|
||||
fasthttp.ReleaseRequest(req)
|
||||
}()
|
||||
|
||||
uri := req.URI()
|
||||
uri.SetHost(g.Addr)
|
||||
uri.SetPath(method)
|
||||
uri.QueryArgs().Add("key", g.ContentKey)
|
||||
if g.client.IsTLS {
|
||||
uri.SetScheme("https")
|
||||
}
|
||||
|
||||
for _, param := range params {
|
||||
param.Apply(&req.Header, uri.QueryArgs())
|
||||
}
|
||||
g.setupRequest(path, req)
|
||||
g.applyParams(params, req)
|
||||
|
||||
err = g.client.DoTimeout(req, res, g.QueryTimeout)
|
||||
if err != nil {
|
||||
@@ -78,7 +75,6 @@ func (g *HTTPClient) doQuery(method string, v easyjson.Unmarshaler, params ...Qu
|
||||
resBytes := res.Body()
|
||||
if resBytes == nil && v == nil {
|
||||
return fmt.Errorf("nothing to unmarshal")
|
||||
|
||||
}
|
||||
if resBytes == nil {
|
||||
return
|
||||
@@ -89,13 +85,53 @@ func (g *HTTPClient) doQuery(method string, v easyjson.Unmarshaler, params ...Qu
|
||||
return
|
||||
}
|
||||
|
||||
// GetPageBySlug returns the only one page using slug filter
|
||||
func (g *HTTPClient) GetPageBySlug(slug string) (pages *Pages, err error) {
|
||||
// setupRequest does the necessary initial configuration to the http request
|
||||
func (g *HTTPClient) setupRequest(path string, req *fasthttp.Request) {
|
||||
|
||||
pages = &Pages{}
|
||||
uri := req.URI()
|
||||
|
||||
scheme := "http"
|
||||
if g.Secured {
|
||||
scheme = "https"
|
||||
}
|
||||
|
||||
uri.SetHost(g.Addr)
|
||||
uri.SetPath(path)
|
||||
uri.SetScheme(scheme)
|
||||
|
||||
uri.QueryArgs().Add("key", g.ContentKey)
|
||||
|
||||
for hKey, hValue := range g.Headers {
|
||||
req.Header.Add(hKey, hValue)
|
||||
}
|
||||
}
|
||||
|
||||
// applyParams function additionally configure the http request using params
|
||||
func (g *HTTPClient) applyParams(p params.Params, req *fasthttp.Request) (err error) {
|
||||
|
||||
uri := req.URI()
|
||||
|
||||
limit := p.Limit
|
||||
if limit > 0 {
|
||||
uri.QueryArgs().Add("limit", strconv.Itoa(limit))
|
||||
}
|
||||
|
||||
page := p.Page
|
||||
if page > 1 {
|
||||
uri.QueryArgs().Add("page", strconv.Itoa(page))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// GetPageBySlug returns the only one page using slug filter
|
||||
func (g *HTTPClient) GetPageBySlug(slug string, queryModifiers ...params.Modifier) (pages *data.Pages, err error) {
|
||||
|
||||
pages = &data.Pages{}
|
||||
defaultParams := params.Params{}
|
||||
method := fmt.Sprintf(ghostAPIGetPageBySlug, slug)
|
||||
|
||||
err = g.doQuery(method, pages)
|
||||
err = g.doQuery(method, pages, defaultParams)
|
||||
if err != nil {
|
||||
pages = nil
|
||||
}
|
||||
@@ -104,10 +140,13 @@ func (g *HTTPClient) GetPageBySlug(slug string) (pages *Pages, err error) {
|
||||
}
|
||||
|
||||
// GetPosts returns posts
|
||||
func (g *HTTPClient) GetPosts(params ...QueryParam) (posts *Posts, err error) {
|
||||
func (g *HTTPClient) GetPosts(queryModifiers ...params.Modifier) (posts *data.Posts, err error) {
|
||||
|
||||
posts = &Posts{}
|
||||
err = g.doQuery(ghostAPIGetPosts, posts, params...)
|
||||
posts = &data.Posts{}
|
||||
defaultParams := params.Params{}
|
||||
combinedParams := params.Modifiers(queryModifiers).Apply(defaultParams)
|
||||
|
||||
err = g.doQuery(ghostAPIGetPosts, posts, combinedParams)
|
||||
if err != nil {
|
||||
posts = nil
|
||||
}
|
||||
@@ -116,12 +155,14 @@ func (g *HTTPClient) GetPosts(params ...QueryParam) (posts *Posts, err error) {
|
||||
}
|
||||
|
||||
// GetPostBySlug returns the only one post using slug filter
|
||||
func (g *HTTPClient) GetPostBySlug(slug string, params ...QueryParam) (posts *Posts, err error) {
|
||||
func (g *HTTPClient) GetPostBySlug(slug string, queryModifiers ...params.Modifier) (posts *data.Posts, err error) {
|
||||
|
||||
posts = &Posts{}
|
||||
posts = &data.Posts{}
|
||||
defaultParams := params.Params{}
|
||||
combinedParams := params.Modifiers(queryModifiers).Apply(defaultParams)
|
||||
method := fmt.Sprintf(ghostAPIGetPostBySlug, slug)
|
||||
|
||||
err = g.doQuery(method, posts, params...)
|
||||
err = g.doQuery(method, posts, combinedParams)
|
||||
if err != nil {
|
||||
posts = nil
|
||||
}
|
||||
@@ -1,18 +1,22 @@
|
||||
package renderer
|
||||
package routes
|
||||
|
||||
import (
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/content"
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/ghost"
|
||||
routing "github.com/jackwhelpton/fasthttp-routing/v2"
|
||||
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/content"
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost/params"
|
||||
)
|
||||
|
||||
// blog handler renders blog data
|
||||
func (r *Renderer) blog(c *routing.Context) (err error) {
|
||||
func (r *Routes) blog(c *routing.Context) (err error) {
|
||||
|
||||
postsPerPage := r.ContentConfig.PostsPerPage
|
||||
currentPage := c.QueryArgs().GetUintOrZero("page")
|
||||
|
||||
latestPosts, err := r.GhostClient.GetPosts(ghost.QueryLimit(postsPerPage), ghost.QueryPage(currentPage))
|
||||
latestPosts, err := r.GhostClient.GetPosts(
|
||||
params.WithLimit(postsPerPage),
|
||||
params.WithPage(currentPage),
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -1,16 +1,17 @@
|
||||
package renderer
|
||||
package routes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/content"
|
||||
routing "github.com/jackwhelpton/fasthttp-routing/v2"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/content"
|
||||
)
|
||||
|
||||
// errorNotFound renders http error-404 template
|
||||
func (r *Renderer) errorNotFound(c *routing.Context) (err error) {
|
||||
func (r *Routes) errorNotFound(c *routing.Context) (err error) {
|
||||
|
||||
errorContent := content.Error{Message: "not found"}
|
||||
|
||||
@@ -18,7 +19,7 @@ func (r *Renderer) errorNotFound(c *routing.Context) (err error) {
|
||||
}
|
||||
|
||||
// useErrorHandler is the middleware that catch handlers errors and render error template
|
||||
func (r *Renderer) useErrorHandler(c *routing.Context) (err error) {
|
||||
func (r *Routes) useErrorHandler(c *routing.Context) (err error) {
|
||||
|
||||
worker := func() (err error) {
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
package renderer
|
||||
package routes
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/content"
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/ghost"
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/templates"
|
||||
routing "github.com/jackwhelpton/fasthttp-routing/v2"
|
||||
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/content"
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost/params"
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/templates"
|
||||
)
|
||||
|
||||
// rootRedirect redirects the root url to the index using http redirect
|
||||
func (r *Renderer) rootRedirect(c *routing.Context) (err error) {
|
||||
func (r *Routes) rootRedirect(c *routing.Context) (err error) {
|
||||
|
||||
c.Redirect(templates.URLIndex, http.StatusFound)
|
||||
|
||||
@@ -18,7 +19,7 @@ func (r *Renderer) rootRedirect(c *routing.Context) (err error) {
|
||||
}
|
||||
|
||||
// index handler renders index data
|
||||
func (r *Renderer) index(c *routing.Context) (err error) {
|
||||
func (r *Routes) index(c *routing.Context) (err error) {
|
||||
|
||||
pinnedPageSlug := r.ContentConfig.Pinned
|
||||
postsPerPage := r.ContentConfig.PostsPerPage
|
||||
@@ -28,7 +29,7 @@ func (r *Renderer) index(c *routing.Context) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
latestPosts, err := r.GhostClient.GetPosts(ghost.QueryLimit(postsPerPage))
|
||||
latestPosts, err := r.GhostClient.GetPosts(params.WithLimit(postsPerPage))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
package renderer
|
||||
package routes
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/templates"
|
||||
routing "github.com/jackwhelpton/fasthttp-routing/v2"
|
||||
"github.com/valyala/fasthttp"
|
||||
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/templates"
|
||||
)
|
||||
|
||||
var _ routing.DataWriter = (*TemplateWriter)(nil)
|
||||
@@ -30,7 +31,7 @@ func (tw *TemplateWriter) Write(w io.Writer, content interface{}) error {
|
||||
}
|
||||
|
||||
// useTemplateWriter is the routing middleware to set the default data writer
|
||||
func (r *Renderer) useTemplateWriter(c *routing.Context) (err error) {
|
||||
func (r *Routes) useTemplateWriter(c *routing.Context) (err error) {
|
||||
|
||||
c.SetDataWriter(staticWriter)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package renderer
|
||||
package routes
|
||||
|
||||
import (
|
||||
"sync"
|
||||
@@ -6,13 +6,13 @@ import (
|
||||
routing "github.com/jackwhelpton/fasthttp-routing/v2"
|
||||
"github.com/valyala/fasthttp"
|
||||
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/config"
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/ghost"
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/templates"
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/config"
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost"
|
||||
"code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/templates"
|
||||
)
|
||||
|
||||
// Renderer is the main handler that contains all routes handlers
|
||||
type Renderer struct {
|
||||
// Routes is the main handler that contains all routes handlers
|
||||
type Routes struct {
|
||||
GhostClient ghost.Client
|
||||
ContentConfig config.Content
|
||||
|
||||
@@ -25,13 +25,13 @@ type Renderer struct {
|
||||
}
|
||||
|
||||
// Handler invokes the lazy once-initializer and then does the request
|
||||
func (r *Renderer) Handler(ctx *fasthttp.RequestCtx) {
|
||||
func (r *Routes) Handler(ctx *fasthttp.RequestCtx) {
|
||||
r.initOnce.Do(r.init)
|
||||
r.handler(ctx)
|
||||
}
|
||||
|
||||
// init has the renderer initialization
|
||||
func (r *Renderer) init() {
|
||||
func (r *Routes) init() {
|
||||
|
||||
router := routing.New()
|
||||
|
||||
@@ -2,6 +2,7 @@ package templates
|
||||
|
||||
import "html/template"
|
||||
|
||||
// UseFuncs returns a func map with template helpers functions
|
||||
func UseFuncs() template.FuncMap {
|
||||
return template.FuncMap{
|
||||
"add": func(i int) int {
|
||||
Reference in New Issue
Block a user