Skip to content
Snippets Groups Projects
Verified Commit d60458f8 authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

feat: improve error handling

parent d00c5eac
Branches
No related tags found
No related merge requests found
Pipeline #2802 failed
Showing
with 670 additions and 502 deletions
...@@ -7,12 +7,10 @@ import ( ...@@ -7,12 +7,10 @@ import (
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
"golang.org/x/sys/unix"
"gopkg.in/gographics/imagick.v3/imagick" "gopkg.in/gographics/imagick.v3/imagick"
"log" "log"
"net/http" "net/http"
"os" "os"
"os/signal"
) )
var imageProcessDuration = promauto.NewCounterVec(prometheus.CounterOpts{ var imageProcessDuration = promauto.NewCounterVec(prometheus.CounterOpts{
...@@ -28,7 +26,7 @@ var imageProcessDurationWrite = imageProcessDuration.WithLabelValues("write") ...@@ -28,7 +26,7 @@ var imageProcessDurationWrite = imageProcessDuration.WithLabelValues("write")
func main() { func main() {
configFile, err := os.Open("config.yaml") configFile, err := os.Open("config.yaml")
if err != nil { if err != nil {
log.Fatalf("Could not open config file: %s", err.Error()) log.Fatalf("error opening config file: %s", err.Error())
} }
config := shared.LoadConfigFromFile(configFile) config := shared.LoadConfigFromFile(configFile)
...@@ -53,25 +51,17 @@ func main() { ...@@ -53,25 +51,17 @@ func main() {
Handler: metricsMux, Handler: metricsMux,
} }
done := make(chan struct{})
go func() { go func() {
if err := metrics.ListenAndServe(); err != nil && err != http.ErrServerClosed { if err := metrics.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Printf("Error: metrics server error: %s", err.Error()) log.Printf("error in metrics server: %s", err.Error())
} }
close(done) srv.Shutdown()
}() }()
if err := srv.Run(mux); err != nil { if err := srv.Run(mux); err != nil {
log.Fatal(err) log.Printf("error in asynq server: %s", err.Error())
} }
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, unix.SIGTERM, unix.SIGINT)
<-sigs
srv.Shutdown()
if err := metrics.Shutdown(context.Background()); err != nil { if err := metrics.Shutdown(context.Background()); err != nil {
log.Printf("Error: metrics shutdown error: %s", err.Error()) log.Printf("error shutting down metrics server: %s", err.Error())
} }
<-done
} }
@font-face{font-family:'Lato';src:url("/assets/fonts/Lato-Regular.eot");src:url("/assets/fonts/Lato-Regular.eot?#iefix") format("embedded-opentype"),url("/assets/fonts/Lato-Regular.woff2") format("woff2"),url("/assets/fonts/Lato-Regular.woff") format("woff"),url("/assets/fonts/Lato-Regular.ttf") format("truetype");font-style:normal;font-weight:normal;text-rendering:optimizeLegibility}@font-face{font-family:'Lato';src:url("/assets/fonts/Lato-Bold.eot");src:url("/assets/fonts/Lato-Bold.eot?#iefix") format("embedded-opentype"),url("/assets/fonts/Lato-Bold.woff2") format("woff2"),url("/assets/fonts/Lato-Bold.woff") format("woff"),url("/assets/fonts/Lato-Bold.ttf") format("truetype");font-style:normal;font-weight:bold;text-rendering:optimizeLegibility}@font-face{font-family:'Lato';src:url("/assets/fonts/Lato-BoldItalic.eot");src:url("/assets/fonts/Lato-BoldItalic.eot?#iefix") format("embedded-opentype"),url("/assets/fonts/Lato-BoldItalic.woff2") format("woff2"),url("/assets/fonts/Lato-BoldItalic.woff") format("woff"),url("/assets/fonts/Lato-BoldItalic.ttf") format("truetype");font-style:italic;font-weight:bold;text-rendering:optimizeLegibility}@font-face{font-family:'Lato';src:url("/assets/fonts/Lato-Italic.eot");src:url("/assets/fonts/Lato-Italic.eot?#iefix") format("embedded-opentype"),url("/assets/fonts/Lato-Italic.woff2") format("woff2"),url("/assets/fonts/Lato-Italic.woff") format("woff"),url("/assets/fonts/Lato-Italic.ttf") format("truetype");font-style:italic;font-weight:normal;text-rendering:optimizeLegibility}
*{margin:0;padding:0}*:focus{outline:none}*::-moz-focus-inner{border:0}html{height:100%}body{background:#282828;font-family:'Lato', sans-serif;font-size:81.25%;min-height:100%;display:flex;flex-direction:column}.container.centered{flex-grow:1;display:flex;margin:0 auto 64px auto;padding:0 16px;flex-direction:column;justify-content:center;width:100%;max-width:640px}.button{display:block;background:#FFC107;padding:4px 16px;border-radius:2px;box-shadow:0 1px 2px rgba(0,0,0,0.1);color:#282828;text-decoration:none;line-height:24px;cursor:pointer;min-width:40px;text-align:center}.button:hover,.button:focus{background:#FFD54F;box-shadow:0 2px 4px rgba(0,0,0,0.2)}.button[aria-disabled=true],.button:disabled{cursor:default;background:#838383;box-shadow:0 -1px 2px rgba(0,0,0,0.1)}nav.navigation{position:sticky;top:0;background:#333333;box-shadow:0 2px 4px rgba(0,0,0,0.2);padding:0 16px;z-index:100}nav.navigation ul{display:flex;max-width:1024px;margin:0 auto;height:56px;align-items:center}nav.navigation ul li{display:block}@media (max-width: 640px){nav.navigation ul li.images,nav.navigation ul li.albums{display:none}}nav.navigation ul li.title a{display:inline-block;line-height:56px}nav.navigation ul li.title a img{width:32px;height:32px;vertical-align:middle}nav.navigation ul li.spacer{flex-grow:1}nav.navigation ul li:not(.spacer){margin:0 8px}nav.navigation ul li:not(.spacer):first-child{margin-left:0}nav.navigation ul li:not(.spacer):last-child{margin-right:0}.page.upload{flex-grow:1;display:flex;flex-direction:column}.page.upload .alert{padding:16px;margin:16px 0;box-shadow:0 2px 4px rgba(33,33,33,0.2);text-decoration:none;border-radius:2px}.page.upload .alert.success{background:#DCEDC8;color:#689F38;border-color:#689F38}.page.upload .alert.success a{color:#33691E}.page.upload .alert.error{background:#FFEBEE;color:#F44336;border-color:#F44336}.page.upload .alert.error a{color:#D32F2F}.page.upload form.upload{padding:96px 0;box-shadow:0 2px 4px rgba(0,0,0,0.2);text-decoration:none;border-radius:2px;text-align:center;background:#333333}.page.upload form.upload .upload-label{font-size:18pt;color:#fff}.page.upload form.upload label{position:relative;display:inline-block;overflow:hidden}.page.upload form.upload label span.text{position:relative;display:inline-block;background:#FFC107;padding:4px 16px;border-radius:2px;box-shadow:0 1px 2px rgba(0,0,0,0.1);line-height:24px;color:#282828;cursor:pointer;z-index:1}.page.upload form.upload label span.text:hover,.page.upload form.upload label span.text:focus{background:#FFD54F;box-shadow:0 2px 4px rgba(0,0,0,0.2)}.page.upload form.upload label input[type=file]{position:absolute;left:0;right:0;top:0;bottom:0;opacity:0}.page.upload .uploading-images{display:flex;flex-direction:row}.page.upload .uploading-images .images{display:flex;flex-direction:column;align-items:stretch;flex-grow:1}.page.upload .uploading-images .images .detail{margin-bottom:32px}.page.upload .uploading-images .images .detail .image{position:relative}.page.upload .uploading-images .images .detail .image .progress{position:absolute;top:-4px;left:0;right:0;height:4px;display:block;background-color:rgba(255,193,7,0.2);overflow:hidden;transition:opacity 400ms}.page.upload .uploading-images .images .detail .image .progress .indeterminate{background-color:rgba(255,193,7,0.8)}.page.upload .uploading-images .images .detail .image .progress .indeterminate::before{content:'';position:absolute;background-color:inherit;top:0;left:0;bottom:0;will-change:left, right;animation:indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite}.page.upload .uploading-images .images .detail .image .progress .indeterminate::after{content:'';position:absolute;background-color:inherit;top:0;left:0;bottom:0;will-change:left, right;animation:indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;animation-delay:1.125s}.page.upload .uploading-images .images .detail:not(.uploading) .progress{opacity:0}.page.upload.submitted .container.centered{display:none}.page.upload:not(.submitted) .uploading-images{display:none}@keyframes indeterminate{0%{left:-35%;right:100%}60%{left:100%;right:-90%}100%{left:100%;right:-90%}}@keyframes indeterminate-short{0%{left:-200%;right:100%}60%{left:107%;right:-8%}100%{left:107%;right:-8%}}.page.image.detail,.page.upload .uploading-images{display:flex;flex-direction:row;align-items:start;align-self:center;padding:32px 32px 128px;justify-content:center}@media (max-width: 1024px){.page.image.detail,.page.upload .uploading-images{flex-direction:column;padding:32px 0;align-items:stretch;justify-content:start}}.page.image.detail .sidebar,.page.upload .uploading-images .sidebar{width:250px;max-width:640px;margin-left:32px}.page.image.detail .sidebar .url,.page.upload .uploading-images .sidebar .url{background:#333333;border-radius:4px;box-shadow:0 2px 4px rgba(0,0,0,0.4);padding:8px;margin-bottom:8px}@media (max-width: 1024px){.page.image.detail .sidebar .url,.page.upload .uploading-images .sidebar .url{padding:16px;margin-bottom:32px}}.page.image.detail .sidebar .url p,.page.upload .uploading-images .sidebar .url p{color:#ffffff}.page.image.detail .sidebar .url div,.page.upload .uploading-images .sidebar .url div{display:flex;flex-direction:row}.page.image.detail .sidebar .url div input,.page.upload .uploading-images .sidebar .url div input{background:none;color:#fff;opacity:0.4;border:none;flex-shrink:1;display:block;flex-grow:1;width:0;text-overflow:ellipsis}.page.image.detail .sidebar .url div button.copy,.page.upload .uploading-images .sidebar .url div button.copy{display:block;background:#FFC107;padding:4px 16px;border-radius:2px;box-shadow:0 1px 2px rgba(0,0,0,0.1);border:none;font-family:'Lato', sans-serif;font-size:10pt;line-height:24px;margin-left:8px;cursor:pointer}.page.image.detail .sidebar .url div button.copy:hover,.page.image.detail .sidebar .url div button.copy:focus,.page.upload .uploading-images .sidebar .url div button.copy:hover,.page.upload .uploading-images .sidebar .url div button.copy:focus{background:#FFD54F;box-shadow:0 2px 4px rgba(0,0,0,0.2)}.page.image.detail .sidebar .actions,.page.upload .uploading-images .sidebar .actions{background:#333333;border-radius:4px;box-shadow:0 2px 4px rgba(0,0,0,0.4);display:flex;flex-direction:row;margin-bottom:8px}@media (max-width: 1024px){.page.image.detail .sidebar .actions,.page.upload .uploading-images .sidebar .actions{margin-bottom:32px}}.page.image.detail .sidebar .actions .delete-form,.page.image.detail .sidebar .actions .update-form,.page.upload .uploading-images .sidebar .actions .delete-form,.page.upload .uploading-images .sidebar .actions .update-form{display:flex;flex-grow:1;flex-basis:0}.page.image.detail .sidebar .actions .delete-form input[type=submit],.page.image.detail .sidebar .actions .update-form input[type=submit],.page.upload .uploading-images .sidebar .actions .delete-form input[type=submit],.page.upload .uploading-images .sidebar .actions .update-form input[type=submit]{display:block;background:#FFC107;padding:4px 16px;border-radius:2px;box-shadow:0 1px 2px rgba(0,0,0,0.1);border:none;font-family:'Lato', sans-serif;font-size:10pt;line-height:24px;margin:8px;flex-grow:1;cursor:pointer}@media (max-width: 1024px){.page.image.detail .sidebar .actions .delete-form input[type=submit],.page.image.detail .sidebar .actions .update-form input[type=submit],.page.upload .uploading-images .sidebar .actions .delete-form input[type=submit],.page.upload .uploading-images .sidebar .actions .update-form input[type=submit]{margin:16px}}.page.image.detail .sidebar .actions .delete-form input[type=submit]:hover,.page.image.detail .sidebar .actions .delete-form input[type=submit]:focus,.page.image.detail .sidebar .actions .update-form input[type=submit]:hover,.page.image.detail .sidebar .actions .update-form input[type=submit]:focus,.page.upload .uploading-images .sidebar .actions .delete-form input[type=submit]:hover,.page.upload .uploading-images .sidebar .actions .delete-form input[type=submit]:focus,.page.upload .uploading-images .sidebar .actions .update-form input[type=submit]:hover,.page.upload .uploading-images .sidebar .actions .update-form input[type=submit]:focus{background:#FFD54F;box-shadow:0 2px 4px rgba(0,0,0,0.2)}@media (max-width: 1024px){.page.image.detail .sidebar,.page.upload .uploading-images .sidebar{width:auto;margin-left:0;margin-top:32px}}.page.image.detail .detail,.page.upload .uploading-images .detail{max-width:640px;width:100%;background:#333333;border-radius:4px;box-shadow:0 2px 4px rgba(0,0,0,0.4)}.page.image.detail .detail .title,.page.upload .uploading-images .detail .title{line-height:1.25;padding:16px;vertical-align:middle;font-size:14pt;font-weight:normal;color:#eee;background:none;border:none;width:100%;box-sizing:border-box}.page.image.detail .detail .title:not(.fake-input):empty,.page.upload .uploading-images .detail .title:not(.fake-input):empty{display:none}.page.image.detail .detail .title:not(.fake-input):empty+.image,.page.upload .uploading-images .detail .title:not(.fake-input):empty+.image{border-top-left-radius:4px;border-top-right-radius:4px}.page.image.detail .detail .image,.page.upload .uploading-images .detail .image{background:#000;display:flex;flex-direction:row;justify-content:center;align-items:start}.page.image.detail .detail .image img,.page.upload .uploading-images .detail .image img{max-width:100%}.page.image.detail .detail .description,.page.upload .uploading-images .detail .description{line-height:1.25;padding:16px;vertical-align:middle;font-size:11pt;font-weight:normal;color:#eee;background:none;border:none;width:100%;box-sizing:border-box;font-family:'Lato', sans-serif;resize:vertical;white-space:pre-line}.page.image.detail .detail .description:not(.fake-input):empty,.page.upload .uploading-images .detail .description:not(.fake-input):empty{display:none}.page.image.detail .fake-input[contenteditable]:empty:before,.page.upload .uploading-images .fake-input[contenteditable]:empty:before{opacity:0.4;content:attr(placeholder)}.page.image.list{max-width:1024px;margin:8px auto 48px;display:grid;grid-template-columns:repeat(auto-fill, minmax(180px, 1fr));grid-gap:8px;align-self:stretch;width:calc(100% - 16px)}@media (max-width: 600px){.page.image.list{grid-template-columns:repeat(auto-fill, minmax(160px, 1fr))}}.page.image.list .image{padding:8px;position:relative;box-shadow:0 2px 4px rgba(0,0,0,0.2);transition:all 200ms;text-decoration:none;background:#333333;border-radius:2px;will-change:transform}.page.image.list .image:hover,.page.image.list .image:focus{transform:translate(0, -2px);box-shadow:0 4px 6px rgba(0,0,0,0.4)}.page.image.list .image .image-container{display:flex;justify-content:stretch;align-content:stretch;justify-items:stretch;align-items:stretch;flex-direction:column;background:#000000}.page.image.list .image .image-container img{aspect-ratio:1;object-fit:contain}.page.image.list .image .info{display:block;z-index:1;color:#eeeeee;line-height:1.25;font-size:10pt;padding-top:12px}.page.image.list .image .info p{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.page.image.list .image .info p.title{font-weight:600}.page.image.list .image .info p.title span.placeholder{opacity:0.4}ul.pagination{display:flex;flex-direction:row;background:#333;box-shadow:0 2px 4px rgba(0,0,0,0.2);padding:4px 8px;color:#fff;justify-self:center;grid-column-start:1;grid-column-end:-1;max-width:480px;width:calc(100% - 16px)}ul.pagination li.page{appearance:none;list-style:none;margin:4px;padding:0;line-height:24px}ul.pagination li.page.current{display:block;padding:4px 16px;flex-grow:1;text-align:center}
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 1024 1024"> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 1024 1024">
<defs> <defs>
<linearGradient id="linearGradient861" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="0" y2="1024"> <linearGradient id="background" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="1024" y2="0">
<stop stop-color="#FFD54F" offset="0"/>
<stop stop-color="#FFC107" offset="1"/>
</linearGradient>
<linearGradient id="linearGradient859" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="1024" y2="0">
<stop stop-color="#4c4c4c" offset="0"/> <stop stop-color="#4c4c4c" offset="0"/>
<stop stop-color="#1a1a1a" offset="1"/> <stop stop-color="#1a1a1a" offset="1"/>
</linearGradient> </linearGradient>
<linearGradient id="foreground" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="0" y2="1024">
<stop stop-color="#FFD54F" offset="0"/>
<stop stop-color="#FFC107" offset="1"/>
</linearGradient>
</defs> </defs>
<path d="m 188.74089,189.79585 662.14201,29.73874 c 15.33377,0.68868 27.31132,13.69238 26.61678,28.89711 l -31.56963,691.1239 c -0.69457,15.20473 -13.80866,27.08144 -29.14246,26.39277 L 154.64562,936.2096 c -15.33382,-0.68869 -27.3114,-13.69234 -26.61688,-28.89705 l 31.5697,-691.12389 c 0.69454,-15.20473 13.80865,-27.08149 29.14245,-26.39281 z" <path d="m 188.74089,189.79585 662.14201,29.73874 c 15.33377,0.68868 27.31132,13.69238 26.61678,28.89711 l -31.56963,691.1239 c -0.69457,15.20473 -13.80866,27.08144 -29.14246,26.39277 L 154.64562,936.2096 c -15.33382,-0.68869 -27.3114,-13.69234 -26.61688,-28.89705 l 31.5697,-691.12389 c 0.69454,-15.20473 13.80865,-27.08149 29.14245,-26.39281 z"
fill="url(#linearGradient859)"/> fill="url(#background)"/>
<path d="m 366.39565,8.0213922 c -0.26427,0 -0.56628,0 -0.83056,0.037434 C 315.01465,13.037623 264.53971,27.37506 192.20614,57.547318 c -5.28534,2.208639 -8.23003,7.861258 -6.94644,13.439008 67.84104,299.102154 120.12809,595.958244 23.55749,930.024374 -2.49166,8.7222 5.39859,16.8829 14.30816,14.6742 90.86998,-22.49812 101.59166,-28.71226 188.04462,-44.77169 5.09657,-0.93585 8.98507,-5.05366 9.58911,-10.1822 14.9877,-124.95656 17.59261,-250.92386 13.10008,-376.10505 109.3309,120.20238 176.37914,231.30817 243.42738,343.27495 2.26514,3.78088 6.49341,6.02696 10.98595,5.72749 65.04735,-4.15524 98.00518,-13.40158 187.7426,-11.56728 9.66462,0.18716 15.51624,-10.51911 10.04213,-18.45525 C 804.73859,786.32339 726.28913,679.14824 616.5807,555.01523 L 854.88652,302.77319 c 5.47409,-5.87722 3.54872,-15.34817 -3.77523,-18.71728 -36.2423,-16.47121 -73.84368,-33.3542 -143.1193,-42.15131 0,0 -7.51274,0.82355 -10.11763,3.55628 L 430.95223,522.25999 c -9.24934,-170.40214 -30.23967,-338.7828 -51.68302,-500.31294 0,-0.224608 -0.0378,-0.48665 -0.11326,-0.748692 l -0.75505,-3.743456 c -1.13257,-5.615184 -6.15363,-9.6206826 -11.9675,-9.4709444 z" <path d="m 366.39565,8.0213922 c -0.26427,0 -0.56628,0 -0.83056,0.037434 C 315.01465,13.037623 264.53971,27.37506 192.20614,57.547318 c -5.28534,2.208639 -8.23003,7.861258 -6.94644,13.439008 67.84104,299.102154 120.12809,595.958244 23.55749,930.024374 -2.49166,8.7222 5.39859,16.8829 14.30816,14.6742 90.86998,-22.49812 101.59166,-28.71226 188.04462,-44.77169 5.09657,-0.93585 8.98507,-5.05366 9.58911,-10.1822 14.9877,-124.95656 17.59261,-250.92386 13.10008,-376.10505 109.3309,120.20238 176.37914,231.30817 243.42738,343.27495 2.26514,3.78088 6.49341,6.02696 10.98595,5.72749 65.04735,-4.15524 98.00518,-13.40158 187.7426,-11.56728 9.66462,0.18716 15.51624,-10.51911 10.04213,-18.45525 C 804.73859,786.32339 726.28913,679.14824 616.5807,555.01523 L 854.88652,302.77319 c 5.47409,-5.87722 3.54872,-15.34817 -3.77523,-18.71728 -36.2423,-16.47121 -73.84368,-33.3542 -143.1193,-42.15131 0,0 -7.51274,0.82355 -10.11763,3.55628 L 430.95223,522.25999 c -9.24934,-170.40214 -30.23967,-338.7828 -51.68302,-500.31294 0,-0.224608 -0.0378,-0.48665 -0.11326,-0.748692 l -0.75505,-3.743456 c -1.13257,-5.615184 -6.15363,-9.6206826 -11.9675,-9.4709444 z"
fill="url(#linearGradient861)"/> fill="url(#foreground)"/>
</svg> </svg>
.container.fatal {
padding: 16px;
margin: 16px auto;
box-shadow: 0 2px 4px rgba(33, 33, 33, 0.2);
text-decoration: none;
border-radius: 2px;
background: #FFEBEE;
color: #F44336;
border-color: #F44336;
font-size: 14px;
ins {
text-decoration: none;
opacity: 0.75;
}
code:last-child {
display: block;
margin-top: 16px;
}
}
nav.navigation
position: sticky
top: 0
background: #333333
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2)
padding: 0 16px
z-index: 100
ul
display: flex
max-width: 1024px
margin: 0 auto
height: 56px
align-items: center
li
display: block
&.images, &.albums
@media (max-width: 640px)
display: none
&.title
a
display: inline-block
line-height: 56px
img
width: 32px
height: 32px
vertical-align: middle
&.spacer
flex-grow: 1
&:not(.spacer)
margin: 0 8px
&:first-child
margin-left: 0
&:last-child
margin-right: 0
nav.navigation {
position: sticky;
top: 0;
background: #333333;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
padding: 0 16px;
z-index: 100;
ul {
display: flex;
max-width: 1024px;
margin: 0 auto;
height: 56px;
align-items: center;
li {
display: block;
&.images,
&.albums {
@media (max-width: 640px) {
display: none;
}
}
&.title {
a {
display: inline-block;
line-height: 56px;
img {
width: 32px;
height: 32px;
vertical-align: middle;
}
}
}
&.spacer {
flex-grow: 1;
}
&:not(.spacer) {
margin: 0 8px;
&:first-child {
margin-left: 0;
}
&:last-child {
margin-right: 0;
}
}
}
}
}
.page.image.detail, .page.upload .uploading-images
display: flex
flex-direction: row
align-items: start
align-self: center
padding: 32px 32px 128px
justify-content: center
@media (max-width: 1024px)
flex-direction: column
padding: 32px 0
align-items: stretch
justify-content: start
.sidebar
width: 250px
max-width: 640px
margin-left: 32px
.url
background: #333333
border-radius: 4px
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4)
padding: 8px
margin-bottom: 8px
@media (max-width: 1024px)
padding: 16px
margin-bottom: 32px
p
color: #ffffff
div
display: flex
flex-direction: row
input
background: none
color: #fff
opacity: 0.4
border: none
flex-shrink: 1
display: block
flex-grow: 1
width: 0
text-overflow: ellipsis
button.copy
display: block
background: #FFC107
padding: 4px 16px
border-radius: 2px
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1)
border: none
font-family: 'Lato', sans-serif
font-size: 10pt
line-height: 24px
margin-left: 8px
cursor: pointer
&:hover, &:focus
background: #FFD54F
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2)
.actions
background: #333333
border-radius: 4px
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4)
display: flex
flex-direction: row
margin-bottom: 8px
@media (max-width: 1024px)
margin-bottom: 32px
.delete-form, .update-form
display: flex
flex-grow: 1
flex-basis: 0
input[type=submit]
display: block
background: #FFC107
padding: 4px 16px
border-radius: 2px
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1)
border: none
font-family: 'Lato', sans-serif
font-size: 10pt
line-height: 24px
margin: 8px
flex-grow: 1
cursor: pointer
@media (max-width: 1024px)
margin: 16px
&:hover, &:focus
background: #FFD54F
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2)
@media (max-width: 1024px)
width: auto
margin-left: 0
margin-top: 32px
.detail
max-width: 640px
width: 100%
background: #333333
border-radius: 4px
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4)
.title
line-height: 1.25
padding: 16px
vertical-align: middle
font-size: 14pt
font-weight: normal
color: #eee
background: none
border: none
width: 100%
box-sizing: border-box
&:not(.fake-input):empty
display: none
& + .image
border-top-left-radius: 4px
border-top-right-radius: 4px
.image
background: #000
display: flex
flex-direction: row
justify-content: center
align-items: start
img
max-width: 100%
.description
line-height: 1.25
padding: 16px
vertical-align: middle
font-size: 11pt
font-weight: normal
color: #eee
background: none
border: none
width: 100%
box-sizing: border-box
font-family: 'Lato', sans-serif
resize: vertical
white-space: pre-line
&:not(.fake-input):empty
display: none
.fake-input[contenteditable]:empty:before
opacity: 0.4
content: attr(placeholder)
\ No newline at end of file
.page.image.detail, .page.upload .uploading-images {
display: flex;
flex-direction: row;
align-items: start;
align-self: center;
padding: 32px 32px 128px;
justify-content: center;
@media (max-width: 1024px) {
flex-direction: column;
padding: 32px 0;
align-items: stretch;
justify-content: start;
}
.sidebar {
width: 250px;
max-width: 640px;
margin-left: 32px;
.url {
background: #333333;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4);
padding: 8px;
margin-bottom: 8px;
@media (max-width: 1024px) {
padding: 16px;
margin-bottom: 32px;
}
p {
color: #ffffff;
}
div {
display: flex;
flex-direction: row;
input {
background: none;
color: #fff;
opacity: 0.4;
border: none;
flex-shrink: 1;
display: block;
flex-grow: 1;
width: 0;
text-overflow: ellipsis;
}
button.copy {
display: block;
background: #FFC107;
padding: 4px 16px;
border-radius: 2px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
border: none;
font-family: 'Lato', sans-serif;
font-size: 10pt;
line-height: 24px;
margin-left: 8px;
cursor: pointer;
&:hover,
&:focus {
background: #FFD54F;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
}
}
}
.actions {
background: #333333;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4);
display: flex;
flex-direction: row;
margin-bottom: 8px;
@media (max-width: 1024px) {
margin-bottom: 32px;
}
.delete-form,
.update-form {
display: flex;
flex-grow: 1;
flex-basis: 0;
input[type=submit] {
display: block;
background: #FFC107;
padding: 4px 16px;
border-radius: 2px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
border: none;
font-family: 'Lato', sans-serif;
font-size: 10pt;
line-height: 24px;
margin: 8px;
flex-grow: 1;
cursor: pointer;
@media (max-width: 1024px) {
margin: 16px;
}
&:hover,
&:focus {
background: #FFD54F;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
}
}
}
@media (max-width: 1024px) {
width: auto;
margin-left: 0;
margin-top: 32px;
}
}
.detail {
max-width: 640px;
width: 100%;
background: #333333;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4);
.title {
line-height: 1.25;
padding: 16px;
vertical-align: middle;
font-size: 14pt;
font-weight: normal;
color: #eee;
background: none;
border: none;
width: 100%;
box-sizing: border-box;
&:not(.fake-input):empty {
display: none;
& + .image {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
}
}
.image {
background: #000;
display: flex;
flex-direction: row;
justify-content: center;
align-items: start;
img {
max-width: 100%;
}
}
.description {
line-height: 1.25;
padding: 16px;
vertical-align: middle;
font-size: 11pt;
font-weight: normal;
color: #eee;
background: none;
border: none;
width: 100%;
box-sizing: border-box;
font-family: 'Lato', sans-serif;
resize: vertical;
white-space: pre-line;
&:not(.fake-input):empty {
display: none;
}
}
}
.fake-input[contenteditable]:empty:before {
opacity: 0.4;
content: attr(placeholder);
}
}
.page.image.list
max-width: 1024px
margin: 8px auto 48px
display: grid
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr))
grid-gap: 8px
align-self: stretch
width: calc(100% - 16px)
@media (max-width: 600px)
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr))
.image
padding: 8px
position: relative
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2)
transition: all 200ms
text-decoration: none
background: #333333
border-radius: 2px
will-change: transform
&:hover, &:focus
transform: translate(0, -2px)
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.4)
.image-container
display: flex
justify-content: stretch
align-content: stretch
justify-items: stretch
align-items: stretch
flex-direction: column
background: #000000
img
aspect-ratio: 1
object-fit: contain
.info
display: block
z-index: 1
color: #eeeeee
line-height: 1.25
font-size: 10pt
padding-top: 12px
p
white-space: nowrap
text-overflow: ellipsis
overflow: hidden
&.title
font-weight: 600
span.placeholder
opacity: 0.4
.page.image.list {
max-width: 1024px;
margin: 8px auto 48px;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
grid-gap: 8px;
align-self: stretch;
width: calc(100% - 16px);
@media (max-width: 600px) {
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
}
.image {
padding: 8px;
position: relative;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
transition: all 200ms;
text-decoration: none;
background: #333333;
border-radius: 2px;
will-change: transform;
&:hover,
&:focus {
transform: translate(0, -2px);
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.4);
}
.image-container {
display: flex;
justify-content: stretch;
align-content: stretch;
justify-items: stretch;
align-items: stretch;
flex-direction: column;
background: #000000;
img {
aspect-ratio: 1;
object-fit: contain;
}
}
.info {
display: block;
z-index: 1;
color: #eeeeee;
line-height: 1.25;
font-size: 10pt;
padding-top: 12px;
p {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
&.title {
font-weight: 600;
span.placeholder {
opacity: 0.4;
}
}
}
}
}
}
.page.upload
flex-grow: 1
display: flex
flex-direction: column
.alert
padding: 16px
margin: 16px 0
box-shadow: 0 2px 4px rgba(33, 33, 33, 0.2)
text-decoration: none
border-radius: 2px
&.success
background: #DCEDC8
color: #689F38
border-color: #689F38
a
color: #33691E
&.error
background: #FFEBEE
color: #F44336
border-color: #F44336
a
color: #D32F2F
form.upload
padding: 96px 0
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2)
text-decoration: none
border-radius: 2px
text-align: center
background: #333333
.upload-label
font-size: 18pt
color: #fff
label
position: relative
display: inline-block
overflow: hidden
span.text
position: relative
display: inline-block
background: #FFC107
padding: 4px 16px
border-radius: 2px
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1)
line-height: 24px
color: #282828
cursor: pointer
z-index: 1
&:hover, &:focus
background: #FFD54F
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2)
input[type=file]
position: absolute
left: 0
right: 0
top: 0
bottom: 0
opacity: 0
.uploading-images
display: flex
flex-direction: row
.images
display: flex
flex-direction: column
align-items: stretch
flex-grow: 1
.detail
margin-bottom: 32px
.image
position: relative
.progress
position: absolute
top: -4px
left: 0
right: 0
height: 4px
display: block
background-color: rgba(255, 193, 7, 0.2)
overflow: hidden
transition: opacity 400ms
.indeterminate
background-color: rgba(255, 193, 7, 0.8)
&::before
content: ''
position: absolute
background-color: inherit
top: 0
left: 0
bottom: 0
will-change: left, right
animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite
&::after
content: ''
position: absolute
background-color: inherit
top: 0
left: 0
bottom: 0
will-change: left, right
animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite
animation-delay: 1.125s
&:not(.uploading) .progress
opacity: 0
&.submitted .container.centered
display: none
&:not(.submitted) .uploading-images
display: none
@keyframes indeterminate
0%
left: -35%
right: 100%
60%
left: 100%
right: -90%
100%
left: 100%
right: -90%
@keyframes indeterminate-short
0%
left: -200%
right: 100%
60%
left: 107%
right: -8%
100%
left: 107%
right: -8%
\ No newline at end of file
.page.upload {
flex-grow: 1;
display: flex;
flex-direction: column;
.alert {
padding: 16px;
margin: 16px 0;
box-shadow: 0 2px 4px rgba(33, 33, 33, 0.2);
text-decoration: none;
border-radius: 2px;
&.success {
background: #DCEDC8;
color: #689F38;
border-color: #689F38;
a {
color: #33691E;
}
}
&.error {
background: #FFEBEE;
color: #F44336;
border-color: #F44336;
a {
color: #D32F2F;
}
}
}
form.upload {
padding: 96px 0;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
text-decoration: none;
border-radius: 2px;
text-align: center;
background: #333333;
.upload-label {
font-size: 18pt;
color: #fff;
}
label {
position: relative;
display: inline-block;
overflow: hidden;
span.text {
position: relative;
display: inline-block;
background: #FFC107;
padding: 4px 16px;
border-radius: 2px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
line-height: 24px;
color: #282828;
cursor: pointer;
z-index: 1;
&:hover,
&:focus {
background: #FFD54F;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
}
input[type=file] {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
opacity: 0;
}
}
}
.uploading-images {
display: flex;
flex-direction: row;
.images {
display: flex;
flex-direction: column;
align-items: stretch;
flex-grow: 1;
.detail {
margin-bottom: 32px;
.image {
position: relative;
.progress {
position: absolute;
top: -4px;
left: 0;
right: 0;
height: 4px;
display: block;
background-color: rgba(255, 193, 7, 0.2);
overflow: hidden;
transition: opacity 400ms;
.indeterminate {
background-color: rgba(255, 193, 7, 0.8);
&::before {
content: '';
position: absolute;
background-color: inherit;
top: 0;
left: 0;
bottom: 0;
will-change: left, right;
animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
}
&::after {
content: '';
position: absolute;
background-color: inherit;
top: 0;
left: 0;
bottom: 0;
will-change: left, right;
animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
animation-delay: 1.125s;
}
}
}
}
&:not(.uploading) .progress {
opacity: 0;
}
}
}
}
&.submitted .container.centered {
display: none;
}
&:not(.submitted) .uploading-images {
display: none;
}
}
@keyframes indeterminate {
0% {
left: -35%;
right: 100%;
}
60% {
left: 100%;
right: -90%;
}
100% {
left: 100%;
right: -90%;
}
}
@keyframes indeterminate-short {
0% {
left: -200%;
right: 100%;
}
60% {
left: 107%;
right: -8%;
}
100% {
left: 107%;
right: -8%;
}
}
;
ul.pagination
display: flex
flex-direction: row
background: #333
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2)
padding: 4px 8px
color: #fff
justify-self: center
grid-column-start: 1
grid-column-end: -1
max-width: 480px
width: calc(100% - 16px)
li.page
appearance: none
list-style: none
margin: 4px
padding: 0
line-height: 24px
&.current
display: block
padding: 4px 16px
flex-grow: 1
text-align: center
ul.pagination {
display: flex;
flex-direction: row;
background: #333;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
padding: 4px 8px;
color: #fff;
justify-self: center;
grid-column-start: 1;
grid-column-end: -1;
max-width: 480px;
width: calc(100% - 16px);
li.page {
appearance: none;
list-style: none;
margin: 4px;
padding: 0;
line-height: 24px;
&.current {
display: block;
padding: 4px 16px;
flex-grow: 1;
text-align: center;
}
}
}
@font-face @font-face {
font-family: 'Lato' font-family: 'Lato';
src: url('/assets/fonts/Lato-Regular.eot') src: url('/assets/fonts/Lato-Regular.eot');
src: url('/assets/fonts/Lato-Regular.eot?#iefix') format('embedded-opentype'), url('/assets/fonts/Lato-Regular.woff2') format('woff2'), url('/assets/fonts/Lato-Regular.woff') format('woff'), url('/assets/fonts/Lato-Regular.ttf') format('truetype') src: url('/assets/fonts/Lato-Regular.eot?#iefix') format('embedded-opentype'), url('/assets/fonts/Lato-Regular.woff2') format('woff2'), url('/assets/fonts/Lato-Regular.woff') format('woff'), url('/assets/fonts/Lato-Regular.ttf') format('truetype');
font-style: normal font-style: normal;
font-weight: normal font-weight: normal;
text-rendering: optimizeLegibility text-rendering: optimizeLegibility;
}
@font-face @font-face {
font-family: 'Lato' font-family: 'Lato';
src: url('/assets/fonts/Lato-Bold.eot') src: url('/assets/fonts/Lato-Bold.eot');
src: url('/assets/fonts/Lato-Bold.eot?#iefix') format('embedded-opentype'), url('/assets/fonts/Lato-Bold.woff2') format('woff2'), url('/assets/fonts/Lato-Bold.woff') format('woff'), url('/assets/fonts/Lato-Bold.ttf') format('truetype') src: url('/assets/fonts/Lato-Bold.eot?#iefix') format('embedded-opentype'), url('/assets/fonts/Lato-Bold.woff2') format('woff2'), url('/assets/fonts/Lato-Bold.woff') format('woff'), url('/assets/fonts/Lato-Bold.ttf') format('truetype');
font-style: normal font-style: normal;
font-weight: bold font-weight: bold;
text-rendering: optimizeLegibility text-rendering: optimizeLegibility;
}
@font-face @font-face {
font-family: 'Lato' font-family: 'Lato';
src: url('/assets/fonts/Lato-BoldItalic.eot') src: url('/assets/fonts/Lato-BoldItalic.eot');
src: url('/assets/fonts/Lato-BoldItalic.eot?#iefix') format('embedded-opentype'), url('/assets/fonts/Lato-BoldItalic.woff2') format('woff2'), url('/assets/fonts/Lato-BoldItalic.woff') format('woff'), url('/assets/fonts/Lato-BoldItalic.ttf') format('truetype') src: url('/assets/fonts/Lato-BoldItalic.eot?#iefix') format('embedded-opentype'), url('/assets/fonts/Lato-BoldItalic.woff2') format('woff2'), url('/assets/fonts/Lato-BoldItalic.woff') format('woff'), url('/assets/fonts/Lato-BoldItalic.ttf') format('truetype');
font-style: italic font-style: italic;
font-weight: bold font-weight: bold;
text-rendering: optimizeLegibility text-rendering: optimizeLegibility;
}
@font-face @font-face {
font-family: 'Lato' font-family: 'Lato';
src: url('/assets/fonts/Lato-Italic.eot') src: url('/assets/fonts/Lato-Italic.eot');
src: url('/assets/fonts/Lato-Italic.eot?#iefix') format('embedded-opentype'), url('/assets/fonts/Lato-Italic.woff2') format('woff2'), url('/assets/fonts/Lato-Italic.woff') format('woff'), url('/assets/fonts/Lato-Italic.ttf') format('truetype') src: url('/assets/fonts/Lato-Italic.eot?#iefix') format('embedded-opentype'), url('/assets/fonts/Lato-Italic.woff2') format('woff2'), url('/assets/fonts/Lato-Italic.woff') format('woff'), url('/assets/fonts/Lato-Italic.ttf') format('truetype');
font-style: italic font-style: italic;
font-weight: normal font-weight: normal;
text-rendering: optimizeLegibility text-rendering: optimizeLegibility;
\ No newline at end of file }
;
*
margin: 0
padding: 0
*:focus
outline: none
*::-moz-focus-inner
border: 0
html
height: 100%
body
background: #282828
font-family: 'Lato', sans-serif
font-size: 81.25%
min-height: 100%
display: flex
flex-direction: column
.container.centered
flex-grow: 1
display: flex
margin: 0 auto 64px auto
padding: 0 16px
flex-direction: column
justify-content: center
width: 100%
max-width: 640px
.button
display: block
background: #FFC107
padding: 4px 16px
border-radius: 2px
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1)
color: #282828
text-decoration: none
line-height: 24px
cursor: pointer
min-width: 40px
text-align: center
&:hover, &:focus
background: #FFD54F
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2)
&[aria-disabled=true], &:disabled
cursor: default
background: #838383
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.1)
@import "navigation"
@import "page_upload"
@import "page_image_detail"
@import "page_image_list"
@import "pagination"
* {
margin: 0;
padding: 0;
}
*:focus {
outline: none;
}
*::-moz-focus-inner {
border: 0;
}
html {
height: 100%;
}
body {
background: #282828;
font-family: 'Lato', sans-serif;
font-size: 81.25%;
min-height: 100%;
display: flex;
flex-direction: column;
}
.container.centered {
flex-grow: 1;
display: flex;
margin: 0 auto 64px auto;
padding: 0 16px;
flex-direction: column;
justify-content: center;
width: 100%;
max-width: 640px;
}
.button {
display: block;
background: #FFC107;
padding: 4px 16px;
border-radius: 2px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
color: #282828;
text-decoration: none;
line-height: 24px;
cursor: pointer;
min-width: 40px;
text-align: center;
&:hover,
&:focus {
background: #FFD54F;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
&[aria-disabled=true],
&:disabled {
cursor: default;
background: #838383;
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.1);
}
}
@import "navigation";
@import "page_upload";
@import "page_image_detail";
@import "page_image_list";
@import "pagination";
@import "error";
...@@ -19,8 +19,8 @@ type errorDto struct { ...@@ -19,8 +19,8 @@ type errorDto struct {
} }
func formatError(w http.ResponseWriter, data ErrorData, format string) { func formatError(w http.ResponseWriter, data ErrorData, format string) {
if data.Code != 0 { if data.Code == 0 {
data.Code = 500 data.Code = http.StatusInternalServerError
} }
log.Printf( log.Printf(
"A type %d error occured for user %s while accessing %s: %s", "A type %d error occured for user %s while accessing %s: %s",
...@@ -32,7 +32,7 @@ func formatError(w http.ResponseWriter, data ErrorData, format string) { ...@@ -32,7 +32,7 @@ func formatError(w http.ResponseWriter, data ErrorData, format string) {
w.WriteHeader(data.Code) w.WriteHeader(data.Code)
if format == "html" { if format == "html" {
if err := formatTemplate(w, "error.html", data); err != nil { if err := formatTemplate(w, "error.html", data); err != nil {
log.Printf("Error while serving html error for %s", data.URL.Path) log.Printf("error serving html error for %s", data.URL.Path)
return return
} }
} else if format == "json" { } else if format == "json" {
...@@ -40,7 +40,7 @@ func formatError(w http.ResponseWriter, data ErrorData, format string) { ...@@ -40,7 +40,7 @@ func formatError(w http.ResponseWriter, data ErrorData, format string) {
data.URL.Path, data.URL.Path,
data.Error.Error(), data.Error.Error(),
}); err != nil { }); err != nil {
log.Printf("Error while serving json error for %s", data.URL.Path) log.Printf("error serving json error for %s", data.URL.Path)
return return
} }
} }
......
...@@ -14,13 +14,13 @@ import ( ...@@ -14,13 +14,13 @@ import (
func main() { func main() {
configFile, err := os.Open("config.yaml") configFile, err := os.Open("config.yaml")
if err != nil { if err != nil {
log.Fatalf("Could not open config file: %s", err.Error()) log.Fatalf("error opening config file: %s", err.Error())
} }
config := shared.LoadConfigFromFile(configFile) config := shared.LoadConfigFromFile(configFile)
db, err := sql.Open(config.Database.Format, config.Database.Url) db, err := sql.Open(config.Database.Format, config.Database.Url)
if err != nil { if err != nil {
panic(err) log.Fatalf("error connecting to database: %s", err.Error())
} }
pageContext := PageContext{ pageContext := PageContext{
...@@ -46,8 +46,7 @@ func main() { ...@@ -46,8 +46,7 @@ func main() {
w.Write([]byte("OK")) w.Write([]byte("OK"))
}) })
err = http.ListenAndServe(":8080", nil) if err := http.ListenAndServe(":8080", nil); err != nil {
if err != nil { log.Fatalf("error in http server: %s", err.Error())
panic(err)
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment