49 Commits

Author SHA1 Message Date
Luc Didry
ebf9f66e47 🔖 — Bump version (0.15.0) 2023-12-19 14:55:26 +01:00
Luc Didry
ed70fbac2e 🔀 Merge branch 'development' 2023-12-19 14:54:34 +01:00
Luc Didry
af11a1e7ec 🔀 Merge branch 'fix-134' into development 2023-12-19 14:40:40 +01:00
Luc Didry
438ce5050e — Add --nuke option to image command (fix #134) 2023-12-19 14:40:03 +01:00
Luc Didry
d67d66d0fd 🔖 — Bump version (0.14.0) 2023-12-18 04:47:19 +01:00
Luc Didry
cc03ba6d3f 🔀 Merge branch 'development' into 'master'
Development

See merge request fiat-tux/hat-softwares/lutim!94
2023-12-18 03:43:02 +00:00
Luc Didry
5b4f56b9f6 🔀 Merge branch 'update-deps' into 'development'
Update deps

See merge request fiat-tux/hat-softwares/lutim!93
2023-12-18 03:31:42 +00:00
Luc Didry
8b6766f498 🩹 — Update tests and code after dependencies upgrade 2023-12-17 09:51:06 +01:00
Luc Didry
68518dd85c ⬆️ — Upgrade dependencies 2023-12-17 05:37:50 +01:00
Luc Didry
e7d0821cff 🔖 — Bump version (0.13.0) 2023-04-26 13:04:42 +02:00
Luc Didry
121c00167c 🔀 Merge branch 'development' 2023-04-26 13:02:52 +02:00
Luc Didry
c3c3c7a780 🐛 — Fix bug introduced in !87 2023-04-26 12:26:45 +02:00
Luc Didry
47a67a428d Update CHANGELOG 2023-04-26 11:56:57 +02:00
Luc Didry
a9b514a30c 🔀 Merge branch 'issue_129' into 'development'
 Add a config flag to disable API

See merge request fiat-tux/hat-softwares/lutim!87
2023-04-26 09:52:41 +00:00
Luc Didry
680b3d7057 👷 — Fix CI 2023-02-28 08:38:26 +01:00
Luc Didry
18888c05b3 Update changelog 2023-02-27 14:25:21 +01:00
Luc Didry
d0e472fe95 🔀 Merge branch 'yechedmad' into development 2023-02-27 14:17:27 +01:00
Luc Didry
10f1bd58c5 🔥 — Remove zanata stuff 2023-02-27 13:46:45 +01:00
Luc Didry
34be40d928 Fix use of $ip 2023-02-27 12:27:38 +00:00
Luc Didry
e7d87dac3c 🔀 Merge branch 'weblate-lutim-default-theme' into 'development'
Translations update from Weblate

See merge request fiat-tux/hat-softwares/lutim!92
2022-12-31 15:50:39 +00:00
Vri
2bff3fcc51 🌐 — Translated using Weblate (German)
Currently translated at 100.0% (139 of 139 strings)

Translation: Lutim/Default theme
Translate-URL: https://weblate.framasoft.org/projects/lutim/default-theme/de/
2022-12-24 18:38:03 +01:00
Luc Didry
c0da308963 🔀 Merge branch 'weblate-lutim-default-theme' into 'development'
Translations update from Weblate

See merge request fiat-tux/hat-softwares/lutim!91
2022-12-16 09:13:01 +00:00
Дмитрий Кузнецов
8515a2b2c7 🌐 — Translated using Weblate (Russian)
Currently translated at 100.0% (139 of 139 strings)

Translation: Lutim/Default theme
Translate-URL: https://weblate.framasoft.org/projects/lutim/default-theme/ru/
2022-12-15 22:38:00 +01:00
Luc Didry
3dc46ebad5 🔀 Merge branch 'weblate-lutim-default-theme' into 'development'
Translations update from Weblate

See merge request fiat-tux/hat-softwares/lutim!89
2022-07-29 15:56:06 +00:00
Milo Ivir
c5a69e6128 🌐 — Translated using Weblate (Croatian)
Currently translated at 100.0% (139 of 139 strings)

Translation: Lutim/Default theme
Translate-URL: https://weblate.framasoft.org/projects/lutim/default-theme/hr/
2022-07-24 20:36:56 +02:00
Milo Ivir
45b8e6c3e2 🌐 — Added translation using Weblate (Croatian) 2022-07-23 16:07:10 +02:00
Luc Didry
8c40ae36bc 🔀 Merge branch 'ploc-master-patch-88214' into 'development'
feat: update Docker build

See merge request fiat-tux/hat-softwares/lutim!83
2022-06-22 12:07:57 +00:00
Luc Didry
6b5e52fba3 Merge branch 'ansible-tarraform-provisioning' into 'development'
Add lutim_startup.sh

See merge request fiat-tux/hat-softwares/lutim!88
2022-05-13 08:03:43 +00:00
arunodhayamsam
5db403f040 Add lutim_startup.sh 2022-05-13 10:38:08 +05:30
Luc Didry
3a0f39761c Tester aussi le referer sans quoi ça ne peut pas fonctionner (à squasher avec le commit précédent). 2022-05-12 14:19:07 +00:00
brunob
691e0c3592 Add a config flag to disable API
fix #129
2022-05-12 15:35:43 +02:00
Luc Didry
8e4f6c7b22 Merge branch 'ansible-tarraform-provisioning' into 'development'
Adhere to ansible styling guide

See merge request fiat-tux/hat-softwares/lutim!86
2022-04-04 05:54:30 +00:00
arunodhayamsam
21b592cb51 Applied ansible styling best practices and Terraform data sorces 2022-03-31 21:28:11 +05:30
Luc Didry
c15f6dea68 Merge branch 'weblate-lutim-default-theme' into 'development'
Translations update from Weblate

See merge request fiat-tux/hat-softwares/lutim!84
2022-03-29 10:12:52 +00:00
J. Lavoie
c9a5cfdcd4 🌐 — Translated using Weblate (German)
Currently translated at 89.9% (125 of 139 strings)

Translation: Lutim/Default theme
Translate-URL: https://weblate.framasoft.org/projects/lutim/default-theme/de/
2022-03-29 12:09:03 +02:00
J. Lavoie
e4d78e5433 🌐 — Translated using Weblate (German)
Currently translated at 88.4% (123 of 139 strings)

Translation: Lutim/Default theme
Translate-URL: https://weblate.framasoft.org/projects/lutim/default-theme/de/
2022-03-29 12:09:02 +02:00
Berto Te
bb6b0c30a8 Translated using Weblate (Spanish)
Currently translated at 100.0% (139 of 139 strings)

Translation: Lutim/Default theme
Translate-URL: https://weblate.framasoft.org/projects/lutim/default-theme/es/
2022-03-29 12:09:02 +02:00
Luc Didry
a46aab6ffa Merge branch 'ansible-tarraform-provisioning' into 'development'
Added IaC and ConfigManagement

See merge request fiat-tux/hat-softwares/lutim!85
2022-03-29 10:08:59 +00:00
arunodhayamsam
f610608aa1 Added IaC and ConfigManagement 2022-03-29 15:23:51 +05:30
Ploc
52b436657f fix: follow hadolint hints
Follow hadolint best practices in order to have a docker build that is as reliable as possible.

- first best practice is to "Pin versions in apk add. Instead of `apk add <package>` use `apk add <package>=<version>`" (see [DL3018](https://github.com/hadolint/hadolint/wiki/DL3018))
- second best practice is to use "`--no-cache` switch to avoid the need to use `--update`"
2021-12-03 16:50:45 +01:00
Ploc
4486b32da5 fix: image label name
Fix the label "name" of the image so that kaniko build does not fail:

> error building image: error building stage: failed to execute command: failed to process "Let's Upload That Image": unexpected end of statement while looking for matching single-quote
2021-12-03 16:50:34 +01:00
Ploc
17c862ae19 chore: update alpine docker source image
Update alpine docker source image from version 3.9 to version 3.15.
2021-12-03 16:50:28 +01:00
Ploc
124ca306b4 chore: merge shell into Dockerfile
Merge build.sh shell into Dockerfile.
2021-12-03 16:50:22 +01:00
Ploc
7d845b9e64 chore: merge subshell into shell
Merge install-dev-env.sh subshell into build.sh shell.
2021-12-03 16:50:16 +01:00
Ploc
3dd1fdca56 chore: use imagemagick package from alpine
Use imagemagick package from alpine instead of rebuilding it from source.
2021-12-03 16:50:05 +01:00
Ploc
87efb615bb feat: container is able to run as non-root 2021-12-03 16:50:00 +01:00
Ploc
e17a51d8d5 chore: update alpine package list on package install 2021-12-03 16:49:50 +01:00
Ploc
c40d22427a feat: expose container port 2021-12-03 16:49:37 +01:00
nicofrand
4384bd1b9f Add korrigan theme 2021-05-12 16:33:35 +02:00
57 changed files with 5196 additions and 1828 deletions

2
.gitignore vendored
View File

@@ -15,6 +15,8 @@ themes/default/templates/data.html.ep
themes/default/templates/raw.html.ep
themes/default/templates/stats.json.ep
themes/default/templates/partial/raw.js.ep
!themes/korrigan
!themes/korrigan/*
tmp/*
.zanata-cache/*
cover_db/*

View File

@@ -86,6 +86,7 @@ carton:
- local/
dependencies: []
script:
- cpanm -l local Devel::Cover~1.29
- carton install --deployment --without=sqlite --without=postgresql --without=minion --without=cache --without=memcached
when: always

7
.provision/README.md Normal file
View File

@@ -0,0 +1,7 @@
## ansible-role-lutim
An ansible role deploy the application on host machine(Ubuntu 20.04)
## terraform-aws-lutim
A terraform plan creates necessary AWS infrastructure and deploy the lutim. This terraform plan uses the `lutim_startup.sh` script to deploy lufi on AWS and also uses above ansible role `ansible-role-lutim` to configure the application on AWS.

View File

@@ -0,0 +1,50 @@
Ansible-Role-lutim
=========
This role installs the and configures lutim on Debian/Ubuntu servers with nginx web server configuration.
Role Variables
--------------
| Variable name | Value | Description |
| ------------- | ----- | ----------- |
| `app_dir` | /var/www/lutim | Set the application directory for the best practice |
| `lutim_owner` | www-data | Set the application user for the best practice |
| `lutim_group` | www-data | Set the application group for the best practice |
| `_contact` | contact.example.com | Contact option (mandatory), where you have to put some way for the users to contact you. |
| `_secrets` | ffyg7kbkjba | Secrets option (mandotory), which is array of random string. Used by Mojolicious for encrypting session cookies |
| `_project_version` | master | We can chose the project version either Master branch, Dev branch or tag based |
| `_server_name` | IP address (or) CNAME/FQDN | Mention the Server Name for the Nginx configurations |
Sample example of use in a playbook
--------------
The following code has been tested with Ubuntu 20.04
```yaml
- name: "install lutim"
hosts: enter your hosts file
become: yes
role:
- ansible-role-lutim
vars:
lutim_owner: "www-data"
lutim_group: "www-data"
contact: "contact.example.com"
secrets: "yigavlvlivwe"
app_dir: "/var/www/lutim"
project_version: "master"
servername: "IP address (or) CNAME/FQDN"
```
Contributing
------------
Dont hesitate to create a pull request

View File

@@ -0,0 +1,6 @@
#Path of the script
PATH=/var/www/lutim
carton exec script/lutim cron cleanbdd --mode production
carton exec script/lutim cron cleanfiles --mode production
carton exec script/lutim cron watch --mode production

View File

@@ -0,0 +1,5 @@
---
# handlers file for ansible-role-lutim
- name: restart nginx
service: name=nginx state=restarted

View File

@@ -0,0 +1,23 @@
#apprun.yml
---
- name: This command will install the postgress module
ansible.builtin.shell:
cmd: carton install --deployment --without=test --without=sqlite
chdir: "{{ app_dir }}"
- name: Upload application config file
ansible.builtin.template:
src: ../templates/lutim.conf.j2
dest: "{{ app_dir }}/lutim.conf"
- name: App executes
ansible.builtin.shell:
cmd: carton exec hypnotoad script/lutim
chdir: "{{ app_dir }}"
- name: Nginx configuration file add
ansible.builtin.template:
src: ../templates/app.conf
dest: /etc/nginx/conf.d/
mode: '0644'
notify: restart nginx

View File

@@ -0,0 +1,21 @@
---
- name: Copy the cronjob file
ansible.builtin.copy:
src: ../files/cronjob
dest: /etc/cron.d/lutim
owner: www-data
group: www-data
- name: "example cronjob"
ansible.builtin.cron:
name: "cronjob"
state: present
user: www-data
minute: "0"
hour: "0"
day: "*"
month: "*"
weekday: "*"
job: |
carton exec script/lutim cron cleanbdd --mode production; carton exec script/lutim cron cleanfiles --mode production; carton exec script/lutim cron watch --mode production

View File

@@ -0,0 +1,23 @@
# dependencies.yaml
---
- name: Lutim | Update apt cache
ansible.builtin.apt: update_cache=yes
changed_when: no
- name: Install Dependencies
ansible.builtin.apt:
name:
- nginx
- carton
- build-essential
- libssl-dev
- libpq-dev
- libio-socket-ssl-perl
- zlib1g-dev
- libmojo-sqlite-perl
- shared-mime-info
- perlmagick
state: present

View File

@@ -0,0 +1,18 @@
#gitclone
---
- name: clone the repository
ansible.builtin.git:
repo: 'https://framagit.org/fiat-tux/hat-softwares/lutim.git'
dest: "{{ app_dir }}"
clone: yes
update: yes
version: "{{ project_version }}"
- name: Change the owner
ansible.builtin.file:
path: "{{ app_dir }}"
owner: "{{ lutim_owner }}"
group: "{{ lutim_group }}"
state: directory
recurse: yes

View File

@@ -0,0 +1,7 @@
---
# tasks file for ansible-role-lutim
- include: dependencies.yaml
- include: gitclone.yaml
- include: apprun.yaml
- include: cronjob.yaml

View File

@@ -0,0 +1,43 @@
server {
listen 80;
# No need to have a `root` parameter.
server_name {{ _server_name }};
# This is important for user's privacy !
access_log off;
error_log /var/log/nginx/lutim.error.log;
# This is important ! Make it OK with your Lutim configuration
client_max_body_size 40M;
location ~* ^/(img|css|font|js)/ {
try_files $uri @lutim;
add_header Expires "Thu, 31 Dec 2037 23:55:55 GMT";
add_header Cache-Control "public, max-age=315360000";
# HTTPS only header, improves security
#add_header Strict-Transport-Security "max-age=15768000";
}
location / {
try_files $uri @lutim;
# HTTPS only header, improves security
#add_header Strict-Transport-Security "max-age=15768000";
}
location @lutim {
# Adapt this to your configuration
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# If you want to log the remote port of the image senders, you'll need that
proxy_set_header X-Remote-Port $remote_port;
proxy_set_header X-Forwarded-Proto $scheme;
# We expect the downsteam servers to redirect to the right hostname, so don't do any rewrites here.
proxy_redirect off;
}
}

View File

@@ -0,0 +1,317 @@
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
{
####################
# Hypnotoad settings
####################
# see http://mojolicio.us/perldoc/Mojo/Server/Hypnotoad for a full list of settings
hypnotoad => {
# array of IP addresses and ports you want to listen to
listen => ['http://127.0.0.1:8080'],
# if you use Lutim behind a reverse proxy like Nginx, you want to set proxy to 1
# if you use Lutim directly, let it commented
#proxy => 1,
},
################
# Lutim settings
################
# put a way to contact you here and uncomment it
# mandatory
contact => '{{ _contact }}',
# random string used to encrypt cookies
# mandatory
secrets => ['{{ _secrets }}'],
# choose a theme. See the available themes in `themes` directory
# optional, default is 'default'
#theme => 'default',
# length of the images random URL
# optional, default is 8
#length => 8,
# length of the encryption key
# optional, default is 8
#crypto_key_length => 8,
# how many URLs will be provisioned in a batch ?
# optional, default is 5
#provis_step => 5,
# max number of URLs to be provisioned
# optional, default is 100
#provisioning => 100,
# anti-flood protection delay, in seconds
# users won't be able to ask Lutim to download images more than one per anti_flood_delay seconds
# optional, default is 5
#anti_flood_delay => 5,
# twitter account which will appear on twitter cards
# see https://dev.twitter.com/docs/cards/validation/validator to register your Lutim instance on twitter
# optional, no default
#tweet_card_via => '@foo',
# max image size, in octets
# you can write it 10*1024*1024
# optional, default is 10485760
#max_file_size => 10485760,
# if you want to have piwik statistics, provide a piwik image tracker
# only the image tracker is allowed, no javascript
# optional, no default
#piwik_img => 'https://piwik.example.org/piwik.php?idsite=1&amp;rec=1',
# if you want to include something in the right of the screen, put it here
# here's an example to put the logo of your hoster
# optional, no default
#hosted_by => 'My super hoster <img src="http://hoster.example.com" alt="Hoster logo">',
# DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED
# Lutim now checks if the X-Forwarded-Proto header is present and equal to https.
# set to 1 if you use Lutim behind a secure web server
# optional, default is 0
#https => 0,
# broadcast_message which will displayed on all pages of Lutim (but no in json response)
# optional, no default
#broadcast_message => 'Maintenance',
# array of authorized domains for API calls.
# if you want to authorize everyone to use the API: ['*']
# optional, no domains allowed by default
#allowed_domains => ['http://1.example.com', 'http://2.example.com'],
# default time limit for files
# valid values are 0, 1, 7, 30 and 365
# optional, default is 0 (no limit)
#default_delay => 0,
# comma-separated values proposed for delays
# optional, default is '0,1,7,30,365'
#proposed_delays => '0,1,7,30,365',
# number of days after which the images will be deleted, even if they were uploaded with "no delay" (or value superior to max_delay)
# a warning message will be displayed on homepage
# optional, default is 0 (no limit)
#max_delay => 0,
# if set to 1, all the images will be encrypted and the encryption option will no be displayed
# optional, default is 0
#always_encrypt => 0,
# you can allow to use a watermark on the uploaded images (or enforce its use)
# define a path to the watermark image (provide an image with alpha channel)
# you can define the path relative to lutim directory or set an absolute path
# to disable the usage of a watermark, leave it blank or commented
# optional, no default
#watermark_path => '',
# the watermark can be a tiling one or a single one
# when using a small one, you can choose where to place it
# valid values are 'Center', 'North', 'NorthEast', 'East', 'SouthEast', 'South', 'SouthWest', 'West' and 'NorthWest' (case insensitive)
# optional, default is 'SouthEast'
#watermark_placement => 'SouthEast',
# choose which watermark (tiling, single or none) should be used by default
# valid values are 'tiling', 'single' or 'none' (case insensitive)
# optional, default is 'none'
#watermark_default => 'none',
# choose which watermark (tiling, single or none) should be enforced (users will always have a watermark and wont be able to disable it)
# valid values are 'tiling', 'single' or 'none' (case insensitive)
# optional, default is 'none'
#watermark_enforce => 'none',
# length of the image's delete token
# optional, default is 24
#token_length => 24,
# URL sub-directory in which you want Lutim to be accessible
# example: you want to have Lutim under https://example.org/lutim/
# => set prefix to '/lutim' or to '/lutim/', it doesn't matter
# optional, defaut is /
#prefix => '/',
# choose what database you want to use
# valid choices are sqlite and postgresql (all lowercase)
# optional, default is sqlite
#dbtype => 'sqlite',
# SQLite ONLY - only used if dbtype is set to sqlite
# define a path to the SQLite database
# you can define it relative to lutim directory or set an absolute path
# remember that it has to be in a directory writable by Lutim user
# optional, default is lutim.db
#db_path => 'lutim.db',
# PostgreSQL ONLY - only used if dbtype is set to postgresql
# these are the credentials to access the PostgreSQL database
# mandatory if you choosed postgresql as dbtype
pgdb => {
database => 'lutim',
host => 'localhost',
user => 'DBUSER',
pwd => 'DBPASSWORD'
},
# use Minion instead of directly increase counters
# need to launch a minion worker service if enabled
# optional, Minion is disabled by default
minion => {
enabled => 0,
# # Which Minion backend to use?
# # valid values are sqlite and postgresql (all lowercase)
# # mandatory if Minion is enabled, default is sqlite
# dbtype => 'sqlite',
# # SQLite ONLY - only used if if you choose sqlite as Minion backend, define the path to the minion database
# # you can define it relative to lutim directory or set an absolute path
# # remember that it has to be in a directory writable by Lutim user
# # optional, default is minion.db
db_path => 'minion.db',
# # PostgreSQL ONLY - only used if you choose postgresql as Minion backend
# # these are the credentials to access the Minion's PostgreSQL database
# # mandatory if you choosed postgresql as Minion backend, no default
pgdb => {
database => 'lutim_minion',
host => 'localhost',
user => 'DBUSER',
pwd => 'DBPASSWORD'
}
},
# set `ldap` if you want that only authenticated users can shorten URLs
# please note that everybody can still use shortend URLs
# optional, no default
#ldap => {
# uri => 'ldaps://ldap.example.org', # server URI
# user_tree => 'ou=users,dc=example,dc=org', # search base DN
# bind_dn => 'uid=ldap_user,ou=users,dc=example,dc=org', # search bind DN
# bind_pwd => 'secr3t', # search bind password
# user_attr => 'uid', # user attribute (uid, mail, sAMAccountName, etc.)
# user_filter => '(!(uid=ldap_user))', # user filter (to exclude some users, etc.)
#},
# set `htpasswd` if you want to use an htpasswd file instead of ldap
# create the file with `htpasswd -c lutim.passwd user`, update it with `htpasswd lutim.passwd user2`
# make sure that lutim can read the file!
# optional, no default
#htpasswd => 'lutim.passwd',
# if you've set ldap or htpasswd above, the session will last `session_duration` seconds before
# the user needs to reauthenticate
# optional, default is 3600
#session_duration => 3600,
# disable counters of images
# set to 1 to disable counters
# optional, counters are enabled by default
#disable_img_stats => 0,
# define the height of the thumbnails generated at users' will
# this is not the height of the thumbnails send after upload,
# we're talking about thumbnails generated when someone asked for
# https://example.org/lutim/tesrinp?thumb
# this works only if you have ImageMagick
# optional, default is 100 (pixels)
#thumbnail_size => 100,
# maximum number of files that can be downloaded as a single zip archive
# if too many files are asked, it results a timeout, so Lutim split the zip URL
# in multiple URLs, each with max_file_size images.
# timeout behavior depends heavily on your server ressources (CPU) and if images
# are encrypted
# optional, default is 15
#max_files_in_zip => 15,
# maximum size (in MB) of memory allowed for the image cache
# Lutim has a built-in memory-based image cache to accelerate responses to often-viewed images.
# This setting makes the cache remove oldest viewed image if the cache size is over it.
# WARNING: a cache is created for each hypnotoad worker, which by default is twice the number of
# CPUs you have. See http://mojolicious.org/perldoc/Mojo/Server/Hypnotoad#workers for details
# So, if you have 4 workers and set cache_max_size to 100, the real maximum size of RAM used for
# cache is 400MB.
# If set to 0, the cache is disabled
# optional, default is 0
#cache_max_size => 0,
# array of memcached servers to cache URL in order to accelerate responses to often-viewed URL.
# If set to [], the use of memcached is disabled.
# If you use memcached, the internal cache (see cache_max_size option above) will not be used.
# Please see https://framagit.org/luc/lutim/wikis/memcached to know how to configure your memcached
# servers.
# exemple of valid value: ['127.0.0.1:11211']
# optional, default is []
#memcached_servers => [],
# enable or disable Lutim built-in logs
# set to 1 to disable logs
# optional, default is 0
#quiet_logs => 0,
# Content-Security-Policy header that will be sent by Lstu
# Set to '' to disable CSP header
# https://content-security-policy.com/ provides a good documentation about CSP.
# https://report-uri.com/home/generate provides a tool to generate a CSP header.
# optional, default is "base-uri 'self'; connect-src 'self'; default-src 'none'; font-src 'self'; form-action 'self'; img-src 'self' data:; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'"
# NB: unsafe-inline for script-src and style-src are here only because morris,
# the graph library used in the stats page requires it
# the default value is good for `default` theme
#csp => "base-uri 'self'; connect-src 'self'; default-src 'none'; font-src 'self'; form-action 'self'; img-src 'self' data:; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'",
# X-Frame-Options header that will be sent by Lstu
# Valid values are: 'DENY', 'SAMEORIGIN', 'ALLOW-FROM https://example.com/'
# Set to '' to disable X-Frame-Options header
# See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
# Please note that this will add a "frame-ancestors" directive to the CSP header (see above) accordingly
# to the chosen setting (See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors)
# optional, default is 'DENY'
#x_frame_options => 'DENY',
# X-Content-Type-Options that will be sent by Lstu
# See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
# Set to '' to disable X-Content-Type-Options header
# optional, default is 'nosniff'
#x_content_type_options => 'nosniff',
# X-XSS-Protection that will be sent by Lstu
# See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection
# Set to '' to disable X-XSS-Protection header
# optional, default is '1; mode=block'
#x_xss_protection => '1; mode=block',
# if set, the uploaded images will use this domain
# optional
#fixed_domain => 'example.org',
##########################
# Lutim cron jobs settings
##########################
# number of days shown in /stats page (used with script/lutim cron stats)
# optional, default is 365
stats_day_num => 365,
# number of days senders' IP addresses are kept in database
# after that delay, they will be deleted from database (used with script/lutim cron cleanbdd)
# optional, default is 365
keep_ip_during => 365,
# max size of the files directory, in octets
# used by script/lutim cron watch to trigger an action
# optional, no default
max_total_size => 10*1024*1024*1024,
# default action when files directory is over max_total_size (used with script/lutim cron watch)
# valid values are 'warn', 'stop-upload' and 'delete'
# please, see readme
# optional, default is 'warn'
#policy_when_full => 'warn',
# images which are not viewed since delete_no_longer_viewed_files days will be deleted by the cron cleanfiles task
# if delete_no_longer_viewed_files is not set, the no longer viewed files will NOT be deleted
# optional, no default
delete_no_longer_viewed_files => 90
};

View File

@@ -0,0 +1,16 @@
---
# vars file for ansible-role-lutim
lutim_owner: "www-data"
lutim_group: "www-data"
app_dir: "/var/www/lutim"
_contact: ""
_secrets: ""
_project_version: ""
_servername: ""

View File

@@ -0,0 +1,92 @@
# Terraform-AWS-Deploy
This terraform plan create the resourcess of EC2 instance
## Terraform Variables
Edit the `vars.tf` file to add the variables as per your need.
| Variable name | Value | Description |
| ------------- | ----- | ----------- |
| `aws_region` | us-east-1 | Set the region |
| `vpc_cidr` | 10.0.0.0/16 | Set the cidr value for the vpc |
| `public_subnet_cidr` | 10.0.2.0/24 | Set the cidr value for the public subnet |
| `user` | ubuntu | Set the EC2 instance user name |
| `public_key` | /home/user_name/.ssh/id_rsa_pub | Set the publickey value for the ec2 instance from the host machine |
| `private_key` | /home/user_name/.ssh/id_rsa | Set the private key value for the ec2 instance from the hostmachine |
| `aws_access_key` | AWSACCESSKEY | Enter your aws access key |
| `aws_secrete_key` | AWSSECRETEKEY | Enter your aws secrete key |
| `instance_name` | lutim_app_instance | Set the name for instance |
| `app_dir` | /var/www/lutim | Set the application directory for the best practice |
| `lutim_owner` | www-data | Set the application user for the best practice |
| `lutim_group` | www-data | Set the application group for the best practice |
| `contact` | contact.example.com | Contact option (mandatory), where you have to put some way for the users to contact you. |
| `contact_user` | name | Name of the user |
| `secrets` | ffyg7kbkjba | Secrets option (mandotory), which is array of random string. Used by Mojolicious for encrypting session cookies |
| `app_dir` | /var/www/lutim | Set the application directory for the best practice |
| `lutim_owner` | www-data | Set the application user for the best practice |
| `lutim_group` | www-data | Set the application group for the best practice |
| `contact` | contact.example.com | Contact option (mandatory), where you have to put some way for the users to contact you. |
| `contact_user` | name | Name of the user |
| `secrets` | ffyg7kbkjba | Secrets option (mandotory), which is array of random string. Used by Mojolicious for encrypting session cookies |
## Usage of terraform plan with lufi deploy script
```sh
git clone https://framagit.org/fiat-tux/hat-softwares/lutim.git
cd lutim/.provision/terraform-aws-lutim
terraform init
terraform plan
terraform apply
```
## Usage of terraform plan with ansible role
- Comment out the below `locals` and `user_data` source in __main.tf__ file
```hcl
locals {
user_data_vars = {
user = var.lutim_owner
group = var.lutim_group
directory = var.app_dir
contact_user = var.contact_user
contact_lutim = var.contact
secret_lutim = var.secret
}
}
```
```hcl
user_data = templatefile("${path.module}/lutim_startup.sh", local.user_data_vars)
```
- Add the below provisioner data in __main.tf__ file at the `aws_instance` resource
```sh
connection {
agent = false
type = "ssh"
host = aws_instance.ec2_instance.public_dns
private_key = "${file(var.private_key)}"
user = "${var.user}"
}
provisioner "remote-exec" {
inline = [
"sudo apt update -y",
"sudo apt install python3.9 -y",
]
}
provisioner "local-exec" {
command = <<EOT
sleep 120 && \
> hosts && \
echo "[Lutim]" | tee -a hosts && \
echo "${aws_instance.ec2_instance.public_ip} ansible_user=${var.user} ansible_ssh_private_key_file=${var.private_key}" | tee -a hosts && \
export ANSIBLE_HOST_KEY_CHECKING=False && \
ansible-playbook -u ${var.user} --private-key ${var.private_key} -i hosts site.yml
EOT
}
```

View File

@@ -0,0 +1,66 @@
#!/bin/bash
echo "**********************************************************************"
echo " *"
echo "Install dependencies *"
echo " *"
echo "**********************************************************************"
SUDO=sudo
$SUDO apt update
$SUDO apt install jq -y
$SUDO apt install wget -y
$SUDO apt install unzip
$SUDO apt install carton -y
$SUDO apt install build-essential -y
$SUDO apt install nginx -y
$SUDO apt install libssl-dev -y
$SUDO apt install libio-socket-ssl-perl -y
$SUDO apt install liblwp-protocol-https-perl -y
$SUDO apt install zlib1g-dev -y
$SUDO apt install libmojo-sqlite-perl -y
$SUDO apt install libpq-dev -y
echo "**********************************************************************"
echo " *"
echo "Configuring the Application *"
echo " *"
echo "**********************************************************************"
sleep 10;
version=$(curl -s https://framagit.org/api/v4/projects/1/releases | jq '.[]' | jq -r '.name' | head -1)
echo $version
pushd ${directory}
$SUDO wget https://framagit.org/fiat-tux/hat-softwares/lutim/-/archive/$version/lutim-$version.zip
$SUDO unzip lutim-$version.zip
$SUDO chown ${user} lutim-$version
$SUDO chgrp ${group} lutim-$version
pushd lutim-$version
echo "**********************************************************************"
echo " *"
echo "Install Carton Packages *"
echo " *"
echo "**********************************************************************"
$SUDO carton install --deployment --without=test --without=sqlite --without=mysql
sleep 10;
$SUDO cp lutim.conf.template lutim.conf
sed -i 's/127.0.0.1/0.0.0.0/' lutim.conf
sed -i 's/#contact/contact/g' lutim.conf
sed -i "s/John Doe/${contact_user}/g" lutim.conf
sed -i "s/admin[at]example.com/${contact_lutim}/g" lutim.conf
sed -i "s/fdjsofjoihrei/${secret_lutim}/g" lutim.conf
sed -i '153 , 158 s/#/ /g' lutim.conf
echo "**********************************************************************"
echo " *"
echo "Run the Application *"
echo " *"
echo "**********************************************************************"
$SUDO carton exec hypnotoad script/lutim

View File

@@ -0,0 +1,123 @@
locals {
user_data_vars = {
user = var.lutim_owner
group = var.lutim_group
directory = var.app_dir
contact_user = var.contact_user
contact_lutim = var.contact
secret_lutim = var.secret
}
}
#Create the VPC
resource "aws_vpc" "vpc" {
cidr_block = "${var.vpc_cidr}"
enable_dns_hostnames = true
enable_dns_support = true
instance_tenancy = "default"
tags = {
Name = "lutim-master-vpc"
}
}
# Create InternetGateWay and attach to VPC
resource "aws_internet_gateway" "IGW" {
vpc_id = "${aws_vpc.vpc.id}"
tags = {
"Name" = "lutim-master-igw"
}
}
# Create a public subnet
resource "aws_subnet" "publicsubnet" {
vpc_id = "${aws_vpc.vpc.id}"
cidr_block = "${var.public_subnet_cidr}"
map_public_ip_on_launch = true
tags = {
Name = "lutim-master-us-east-1-public"
}
}
# Create routeTable
resource "aws_route_table" "publicroute" {
vpc_id = "${aws_vpc.vpc.id}"
route {
cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.IGW.id}"
}
tags = {
Name = "lutim-master-us-east-1-public-rt"
}
}
resource "aws_main_route_table_association" "mainRTB" {
vpc_id = "${aws_vpc.vpc.id}"
route_table_id = "${aws_route_table.publicroute.id}"
}
## Create security group
resource "aws_security_group" "security" {
name = "lutim-master-sg"
description = "allow all traffic"
vpc_id = "${aws_vpc.vpc.id}"
ingress {
description = "allow all traffic"
from_port = "0"
to_port = "65535"
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "allow port SSH"
from_port = "22"
to_port = "22"
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# Add ubuntu AMI
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"]
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}
}
#Create key_pair for the instance
resource "aws_key_pair" "genkey" {
key_name = "lutim.webapp"
public_key = "${file(var.public_key)}"
}
# Craete ec2 instance
resource "aws_instance" "ec2_instance" {
ami = "${data.aws_ami.ubuntu.id}"
instance_type = "t2.medium"
associate_public_ip_address = "true"
subnet_id = "${aws_subnet.publicsubnet.id}"
vpc_security_group_ids = ["${aws_security_group.security.id}"]
user_data = templatefile("${path.module}/lutim_startup.sh", local.user_data_vars)
key_name = "lutim.webapp"
tags = {
Name = "${var.instance_name}"
}
}

View File

@@ -0,0 +1,7 @@
output "public_ip" {
value = "${aws_instance.ec2_instance.public_ip}"
}
output "App_running_at" {
value = "http://${aws_instance.ec2_instance.public_ip}:8080"
}

View File

@@ -0,0 +1,14 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.0"
}
}
}
provider "aws" {
access_key = "${var.aws_access_key}"
secret_key = "${var.aws_secret_key}"
region = "${var.aws_region}"
}

View File

@@ -0,0 +1,60 @@
variable "aws_region" {
default = "aws_region"
}
variable "vpc_cidr" {
default = "cidr_value"
}
variable "public_subnet_cidr" {
default = "cidr_value"
}
variable "public_subnet1_cidr" {
default = "cidr_value"
}
variable "user" {
default = "user_of_instance"
}
variable "public_key" {
default = "$PWD_publickey"
}
variable "private_key" {
default = "$PWD_privatekey"
}
variable "aws_access_key" {
default = "aws_access_key"
}
variable "aws_secret_key" {
default = "aws_secrete_key"
}
variable "instance_name" {
default = "instance_name"
}
variable "lutim_owner" {
default = ""
}
variable "lutim_group" {
default = ""
}
variable "app_dir" {
default = ""
}
variable "contact_user" {
default = ""
}
variable "contact" {
default = ""
}
variable "secret" {
default = ""
}

View File

@@ -1,6 +1,20 @@
Revision history for Lutim
0.13.0 ????-??-??
0.16.0 ????-??-??
0.15.0 2023-12-19
- ✨ — Add --nuke option to image command
0.14.0 2023-12-18
- ⬆️ Update dependencies
- 💥 BREAKING CHANGE: Use `?_format=json` instead of `?format=json`
- 💥 BREAKING CHANGE: Use `?_format=json` instead of terminating the URL with `.json`
0.13.0 2023-04-26
- 💄 — Add Korrigan theme (Nicolas Frandeboeuf)
- 🔥 — Remove zanata stuff
- ✨ — Add a config flag to disable API (@b_b)
- 🌐 — Update translations
0.12.1 2020-10-08
- ⬆️ Update jQuery

View File

@@ -1,10 +1,10 @@
FROM alpine:3.9
FROM alpine:3.15
ARG BUILD_DATE
ARG VCS_REF
ARG VERSION
LABEL org.label-schema.build-date=$BUILD_DATE \
org.label-schema.name="Let's Upload That Image" \
org.label-schema.name="Lets Upload That Image" \
org.label-schema.url="https://lut.im/" \
org.label-schema.vcs-ref=$VCS_REF \
org.label-schema.vcs-url="https://git.framasoft.org/luc/lutim" \
@@ -12,12 +12,37 @@ LABEL org.label-schema.build-date=$BUILD_DATE \
org.label-schema.version=$VERSION \
org.label-schema.schema-version="1.0"
RUN adduser -D lutim
COPY --chown=lutim:lutim . /home/lutim
RUN adduser -D lutim \
&& addgroup lutim root
COPY . /home/lutim
RUN chmod -R g+rwX /home/lutim
WORKDIR /home/lutim
RUN /bin/sh /home/lutim/docker/build.sh
RUN apk --no-cache add perl~=5 \
libpq~=14 \
perl-crypt-rijndael~=1 \
perl-io-socket-ssl~=2 \
perl-net-ssleay~=1 \
su-exec~=0.2 \
shared-mime-info~=2 \
libretls~=3 \
imagemagick~=7 \
imagemagick-perlmagick~=7 \
bash~=~5 \
&& apk --no-cache add --virtual .build-deps build-base~=0.5 \
perl-utils~=5 \
perl-dev~=5 \
postgresql14-dev~=14 \
vim~=8 \
wget~=1 \
zlib-dev~=1 \
&& cpan notest Carton Config::FromHash \
&& carton install --without test \
&& apk del .build-deps \
&& rm -rf /var/cache/apk/* /root/.cpan*
USER lutim
EXPOSE 8080
ENTRYPOINT ["/bin/sh", "/home/lutim/docker/entrypoint.sh"]

View File

@@ -19,9 +19,6 @@ locales:
$(XGETTEXT) $(EXTRACTDIR) -o $(POT) 2>/dev/null
$(XGETTEXT) $(EXTRACTDIR) -o $(ENPO) 2>/dev/null
stats-locales:
wlc stats
podcheck:
podchecker lib/Lutim/DB/Image.pm

View File

@@ -68,3 +68,7 @@ It uses:
* [JSZip](https://stuk.github.io/jszip/) for generating a zip containing all the images in the gallery
* [FileSaver.js](https://github.com/eligrey/FileSaver.js/) for saving the zip
* [Toastify JS](https://apvarun.github.io/toastify-js/) for notifications
## Deploy lutim
An ansible role and a terraform plan reside under the `.provision` directory. An user could utilize the terraform plan if they chose to deploy lutim on AWS, if that's not the goal, they could simply execute the ansible role in part. Usage docs for both are present in their respective directories.

View File

@@ -15,6 +15,7 @@ requires 'Filesys::DiskUsage';
requires 'Switch';
requires 'Crypt::CBC';
requires 'Crypt::Blowfish';
requires 'Digest::MD5';
requires 'Locale::Maketext';
requires 'Locale::Maketext::Extract';
requires 'File::MimeInfo';

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +0,0 @@
#!/usr/bin/env sh
set -eu
apk update
apk add perl libpq perl-crypt-rijndael perl-io-socket-ssl perl-net-ssleay su-exec shared-mime-info libressl
sh $(dirname $0)/install-dev-env.sh
sh $(dirname $0)/install-imagemagick.sh
cpan notest Carton Config::FromHash
carton install --without test
# Remove dev env
apk del .build-deps
rm -rf /var/cache/apk/* /root/.cpan*

6
docker/entrypoint.sh Normal file → Executable file
View File

@@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
set -eu
@@ -14,7 +14,7 @@ then
echo ""
echo "You can then install the build dependencies with this command"
echo " sh ~lutim/docker/install-dev-env.sh"
tail -f /dev/null
exit 0
fi
@@ -28,7 +28,7 @@ then
DB_HOST=$(perl utilities/read_conf.pl pgdb/host db)
DB_PORT=$(perl utilities/read_conf.pl pgdb/port 5432)
fi
if [ -n "$DB_HOST" -a -n "$DB_PORT" ]
if [ -n "$DB_HOST" ] && [ -n "$DB_PORT" ]
then
while ! nc -vz "${DB_HOST}" "${DB_PORT}"; do
echo "Waiting for database..."

View File

@@ -1,3 +0,0 @@
#!/usr/bin/env sh
apk --update add --virtual .build-deps build-base perl-utils perl-dev postgresql-dev vim wget zlib-dev

View File

@@ -1,40 +0,0 @@
#!/usr/bin/env sh
# Instructions from https://imagemagick.org/script/perl-magick.php
set -eu
IM_VERSION=7.0.8-41
SHA256_DIGEST=93f73a245c25194f757c075df9f2ec40010376200cc664c21646565b8690112c
IM_DIR="ImageMagick-$IM_VERSION"
TARBALL="$IM_DIR.tar.gz"
ORIG_DIR="$(pwd)"
apk add libgomp libgcc libmagic \
libjpeg libjpeg-turbo-dev \
libpng libpng-dev \
tiff tiff-dev \
libwebp libwebp-dev
mkdir -p /tmp/im-build
cd /tmp/im-build
echo "$SHA256_DIGEST *$TARBALL" > SHA256SUM
wget https://imagemagick.org/download/$TARBALL -O $TARBALL
sha256sum -c SHA256SUM
tar xvf $TARBALL
cd $IM_DIR
./configure --with-perl --with-jpeg --with-png --with-tiff --with-webp
make -j$(nproc)
make install
ldconfig /usr/local/lib
perl -MImage::Magick -le 'print Image::Magick->QuantumDepth'
cd "$ORIG_DIR"
apk del libjpeg-turbo-dev libpng-dev tiff-dev libwebp-dev
rm -rf /tmp/im-build

View File

@@ -291,7 +291,7 @@ sub startup {
});
$r->get('/')->
over('authorized')->
requires('authorized')->
to('Image#home')->
name('index');
$r->get('/')->
@@ -330,7 +330,7 @@ sub startup {
to('Image#change_lang')->
name('lang');
$r->get('/partial/:file' => sub {
$r->get('/partial/<:file>.<:f>' => sub {
my $c = shift;
$c->render(
template => 'partial/'.$c->param('file'),
@@ -351,7 +351,7 @@ sub startup {
})->name('gallery');
$r->get('/myfiles')->
over('authorized')->
requires('authorized')->
name('myfiles');
$r->get('/myfiles')->
to('Authent#index');
@@ -369,28 +369,28 @@ sub startup {
->name('random');
$r->post('/')->
over('authorized')->
requires('authorized')->
to('Image#add')->
name('add');
$r->post('/')->
to('Authent#index');
$r->get('/d/:short/:token')->
over('authorized')->
requires('authorized')->
to('Image#delete')->
name('delete');
$r->get('/d/:short/:token')->
to('Authent#index');
$r->post('/m/:short/:token')->
over('authorized')->
requires('authorized')->
to('Image#modify')->
name('modify');
$r->post('/m/:short/:token')->
to('Authent#index');
$r->post('/c')->
over('authorized')->
requires('authorized')->
to('Image#get_counter')->
name('counter');
$r->post('/c')->

View File

@@ -46,7 +46,8 @@ sub run {
'r|remove=s{1,}' => \my @remove,
'y|yes' => \my $yes,
'q|quiet' => \my $quiet,
's|search=s' => \my $ip
's|search=s' => \my $ip,
'n|nuke=s' => \my $nuke,
;
if (scalar @info) {
@@ -85,9 +86,43 @@ sub run {
push @shorts, $e->short;
print_infos($e, $csv);
});
say sprintf('%d matching URLs', $u->size);
say sprintf('%d matching images', $u->size);
say sprintf("If you want to delete those images, please do:\n carton exec script/lutim image --remove %s", join(' ', @shorts)) if @shorts;
}
if ($nuke) {
my $i = get_short($c, $nuke);
if ($i && $i->created_by) {
my $u = Lutim::DB::Image->new(app => $c->app)->search_exact_created_by($i->created_by);
my @shorts;
say sprintf('%d images created by the same IP address (%s) than image %s', $u->size, $i->created_by, $nuke);
my $confirm = ($yes) ? 'yes' : undef;
unless (defined $confirm) {
printf('Are you sure you want to remove those %d images? [N/y] ', $u->size);
$confirm = <STDIN>;
chomp $confirm;
}
if ($confirm =~ m/^y(es)?$/i) {
$u->each(sub {
my ($e, $num) = @_;
my $i = get_short($c, $e->short);
if ($i) {
print_infos($i, $csv);
if ($i->enabled) {
delete_short($c, $i, 1);
} else {
say sprintf('The image %s is already disabled', $e->short);
}
}
});
} else {
say 'Answer was not "y" or "yes". Aborting deletion.';
}
} elsif (! $i->created_by) {
say sprintf('Image %s does not contain its creators IP address.', $nuke);
} else {
say sprintf('Sorry, cant find image %s', $nuke);
}
}
}
sub get_short {
@@ -168,7 +203,7 @@ sub delete_short {
my $confirm = ($y) ? 'yes' : undef;
unless (defined $confirm) {
printf('Are you sure you want to remove this image (%s) ? [N/y] ', $i->short);
printf('Are you sure you want to remove this image (%s)? [N/y] ', $i->short);
$confirm = <STDIN>;
chomp $confirm;
}
@@ -191,6 +226,7 @@ Lutim::Command::image - Manage URL in Lutim's database
carton exec script/lutim image --info <short> <short> [--csv] Print infos about the space-separated images (--csv creates a CSV output)
carton exec script/lutim image --remove <short> <short> [--yes] [--quiet] Delete the space-separated images (--yes disables confirmation, --quiet disables informations printing)
carton exec script/lutim image --search <ip> Print infos about the images uploaded by this IP (database LIKE, may include images uploaded by other IPs)
carton exec script/lutim image --nuke <short> Delete the image and all images sent by the same IP address and print infos about the deleted images
=cut

View File

@@ -1,8 +1,8 @@
# vim:set sw=4 ts=4 sts=4 expandtab:
package Lutim::Controller::Image;
use Mojo::Asset::Memory;
use Mojo::Base 'Mojolicious::Controller';
use Mojo::Util qw(url_escape url_unescape b64_encode encode);
use Mojo::Asset::Memory;
use Mojo::JSON qw(true false);
use Lutim::DB::Image;
use DateTime;
@@ -287,6 +287,22 @@ sub add {
my $keep_exif = $c->param('keep-exif');
my $wm = $c->param('watermark');
if ($c->config('disable_api')) {
my $unauthorized_api = (!defined($c->req->headers->referrer) || Mojo::URL->new($c->req->headers->referrer)->host ne Mojo::URL->new('https://'.$c->req->headers->host)->host);
if ($unauthorized_api) {
my $msg = $c->l('Sorry, the API is disabled');
$c->app->log->info('Blocked API call for '.$c->ip(1));
return $c->respond_to(
json => { json => { success => Mojo::JSON->false, msg => $msg } },
any => sub {
shift->render(
template => 'index',
msg => $msg,
);
}
);
}
}
if(!defined($c->stash('stop_upload'))) {
if (defined($file_url) && $file_url) {
if (is_http_uri($file_url) || is_https_uri($file_url)) {
@@ -471,12 +487,10 @@ sub add {
if ($mediatype ne 'image/svg+xml' && $mediatype !~ m#image/(x-)?xcf# && $mediatype ne 'image/webp') {
# Remove the EXIF tags
my $data = new IO::Scalar \$upload->slurp();
my $et = new Image::ExifTool;
my $et = Image::ExifTool->new;
# Use $data in Image::ExifTool object
$et->ExtractInfo($data);
# Remove all metadata
$et->SetNewValue('*', undef);
$et->SetNewValue('*');
# Create a temporary IO::Scalar to write into
my $temp;

View File

@@ -345,6 +345,20 @@ sub to_hash {
=back
=head2 search_exact_created_by
=over 1
=item B<Usage> : C<$c-E<gt>search_exact_created_by($ip)>
=item B<Arguments> : an IP address
=item B<Purpose> : get enabled images that have been uploaded by this IP address
=item B<Returns> : a Mojo::Collection object containing the matching images as Lutim::DB::Image objects
=back
=cut
1;

View File

@@ -213,6 +213,27 @@ sub search_created_by {
return c(@images);
}
sub search_exact_created_by {
my $c = shift;
my $ip = shift;
my @images;
my $records = $c->app->pg->db->select('lutim', undef, { enabled => 1, created_by => $ip })->hashes;
$records->each(
sub {
my ($e, $num) = @_;
my $i = Lutim::DB::Image->new(app => $c->app);
$i->_slurp($e);
push @images, $i;
}
);
return c(@images);
}
sub _slurp {
my $c = shift;
my $r = shift;

View File

@@ -214,6 +214,27 @@ sub search_created_by {
return c(@images);
}
sub search_exact_created_by {
my $c = shift;
my $ip = shift;
my @images;
my $records = $c->app->sqlite->db->select('lutim', undef, { enabled => 1, created_by => $ip })->hashes;
$records->each(
sub {
my ($e, $num) = @_;
my $i = Lutim::DB::Image->new(app => $c->app);
$i->_slurp($e);
push @images, $i;
}
);
return c(@images);
}
sub _slurp {
my $c = shift;
my $r = shift;

View File

@@ -22,6 +22,7 @@ our $default_config = {
watermark_default => 'none',
watermark_enforce => 'none',
theme => 'default',
disable_api => 0,
dbtype => 'sqlite',
db_path => 'lutim.db',
max_files_in_zip => 15,

View File

@@ -8,6 +8,7 @@ use Data::Entropy qw(entropy_source);
use DateTime;
use Mojo::Util qw(decode);
use ISO::639_1;
use Digest::MD5 'md5';
sub register {
my ($self, $app) = @_;
@@ -258,6 +259,18 @@ sub _is_wm_selected {
return ($wm eq $c->config('watermark_default')) ? 'selected="selected"' : '';
}
sub _key_from_key {
my $key = shift;
# Key size for Blowfish is 56
my $ks = 56;
my $material = md5($key);
while (length($material) < $ks) {
$material .= md5($material);
}
return substr($material,0,$ks);
}
sub _crypt {
my $c = shift;
my $upload = shift;
@@ -267,10 +280,12 @@ sub _crypt {
my $iv = $c->shortener(8);
my $cipher = Crypt::CBC->new(
-key => $key,
-cipher => 'Blowfish',
-header => 'none',
-iv => $iv
-key => _key_from_key($key),
-cipher => 'Blowfish',
-header => 'none',
-literal_key => 1,
-pbkdf => 'pbkdf2',
-iv => $iv
);
$cipher->start('encrypting');
@@ -289,16 +304,18 @@ sub _crypt {
sub _decrypt {
my $c = shift;
my $key = shift;
my $key = _key_from_key(shift);
my $file = shift;
my $iv = shift;
$iv = 'dupajasi' unless $iv;
my $cipher = Crypt::CBC->new(
-key => $key,
-cipher => 'Blowfish',
-header => 'none',
-iv => $iv
-key => $key,
-cipher => 'Blowfish',
-header => 'none',
-literal_key => 1,
-pbkdf => 'pbkdf2',
-iv => $iv
);
$cipher->start('decrypting');

View File

@@ -135,6 +135,10 @@
# optional, defaut is /
#prefix => '/',
# if set to 1, Lutim will try to prevent its use without using the web interface
# optional, default is 0
#disable_api => 0,
# choose what database you want to use
# valid choices are sqlite and postgresql (all lowercase)
# optional, default is sqlite

View File

@@ -1,11 +0,0 @@
#!/bin/bash
FILE=$1
if [[ ! -e themes/default/lib/Lutim/I18N/$FILE.po ]]
then
echo "themes/default/lib/Lutim/I18N/$FILE.po does not exist. Exiting."
exit 1
else
LOCALE=$(echo $FILE | sed -e "s@_@-@g")
zanata-cli -q -B push --push-type trans -l $LOCALE
fi

View File

@@ -81,7 +81,7 @@ $t->get_ok('/css/lutim.css')
# Instance settings informations
$t->get_ok('/infos')
->status_is(200)
->json_has('image_magick')
->json_has('/image_magick')
->json_is(
'/always_encrypt' => false,
'/broadcast_message' => 'test broadcast message',
@@ -96,7 +96,7 @@ $t->get_ok('/infos')
my $image = Mojo::File->new($Bin, '..', 'themes', 'default', 'public', 'img', 'Lutim.png')->to_string;
$t->post_ok('/' => form => { file => { file => $image }, format => 'json' })
->status_is(200)
->json_has('msg', 'success')
->json_has('/msg', '/success')
->json_is('/success' => true, '/msg/filename' => 'Lutim.png')
->json_like('/msg/short' => qr#[-_a-zA-Z0-9]{8}#, '/msg/real_short' => qr#[-_a-zA-Z0-9]{8}#, '/msg/token' => qr#[-_a-zA-Z0-9]{24}#);
@@ -138,7 +138,7 @@ my $token = $raw->json('/msg/token');
$t->get_ok('/'.$rshort)
->status_is(200);
$t->get_ok('/d/'.$rshort.'/'.$token, form => { format => 'json' })
$t->get_ok('/d/'.$rshort.'/'.$token, form => { _format => 'json' })
->status_is('200')
->json_is(
{

View File

@@ -12,8 +12,8 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
"PO-Revision-Date: 2020-03-09 16:23+0000\n"
"Last-Translator: Luc Didry <luc@framasoft.org>\n"
"PO-Revision-Date: 2022-12-24 17:38+0000\n"
"Last-Translator: Vri <vrifox@vrifox.cc>\n"
"Language-Team: German <https://weblate.framasoft.org/projects/lutim/"
"default-theme/de/>\n"
"Language: de\n"
@@ -21,7 +21,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 3.11.2\n"
"X-Generator: Weblate 4.14.1\n"
#. (7)
#. (30)
@@ -65,9 +65,8 @@ msgid "An error occured while downloading the image."
msgstr "Beim Herunterladen des Bildes ist ein Fehler aufgetreten."
#: themes/default/templates/zip.html.ep:2
#, fuzzy
msgid "Archives download"
msgstr "Archiv-Download"
msgstr "Herunterladen von Archiv"
#: themes/default/templates/about.html.ep:44 themes/default/templates/myfiles.html.ep:135 themes/default/templates/stats.html.ep:25
msgid "Back to homepage"
@@ -107,11 +106,11 @@ msgstr "Zähler"
#: themes/default/templates/stats.html.ep:18
msgid "Delay repartition chart for disabled images"
msgstr ""
msgstr "Diagramm zur Neuaufteilung der Verzögerung für deaktivierte Bilder"
#: themes/default/templates/stats.html.ep:15
msgid "Delay repartition chart for enabled images"
msgstr ""
msgstr "Diagramm zur Neuaufteilung der Verzögerung für deaktivierte Bilder"
#: themes/default/templates/index.html.ep:133 themes/default/templates/index.html.ep:165 themes/default/templates/index.html.ep:196 themes/default/templates/myfiles.html.ep:124 themes/default/templates/myfiles.html.ep:45 themes/default/templates/partial/lutim.js.ep:161
msgid "Delete at first view?"
@@ -162,7 +161,7 @@ msgstr "Verschlüssle das Bild (Lutim behält den Key nicht)."
#: themes/default/templates/partial/lutim.js.ep:45 themes/default/templates/partial/myfiles.js.ep:113
msgid "Error while trying to modify the image."
msgstr "Beim bearbeiten des Bildes ist ein Fehler aufgetreten."
msgstr "Beim Bearbeiten des Bildes ist ein Fehler aufgetreten."
#: themes/default/templates/stats.html.ep:10
msgid "Evolution of total files"
@@ -174,7 +173,7 @@ msgstr "Läuft ab am"
#: themes/default/templates/myfiles.html.ep:112
msgid "Export localStorage data"
msgstr ""
msgstr "localStorage-Daten exportieren"
#: themes/default/templates/myfiles.html.ep:121
msgid "File name"
@@ -190,7 +189,7 @@ msgstr ""
#: themes/default/templates/partial/navbar.html.ep:80
msgid "Fork me!"
msgstr "Fork me!"
msgstr "Fork mich!"
#: themes/default/templates/index.html.ep:10 themes/default/templates/index.html.ep:13 themes/default/templates/myfiles.html.ep:60 themes/default/templates/myfiles.html.ep:63
msgid "Gallery link"
@@ -230,7 +229,7 @@ msgstr "Bild-URL"
#: lib/Lutim/Command/cron/stats.pm:153 themes/default/templates/raw.html.ep:2
msgid "Image delay"
msgstr ""
msgstr "Bild-Verzögerung"
#: themes/default/templates/partial/common.js.ep:157
msgid "Image deleted"
@@ -242,7 +241,7 @@ msgstr "Bild nicht gefunden."
#: themes/default/templates/myfiles.html.ep:113
msgid "Import localStorage data"
msgstr ""
msgstr "localStorage-Daten importieren"
#: themes/default/templates/partial/navbar.html.ep:69
msgid "Informations"
@@ -294,11 +293,11 @@ msgstr "Links zum teilen auf sozialen Netzwerken"
#: themes/default/templates/login.html.ep:8
msgid "Login"
msgstr "Login"
msgstr "Anmelden"
#: themes/default/templates/partial/navbar.html.ep:33
msgid "Logout"
msgstr "Ausloggen"
msgstr "Abmelden"
#: themes/default/templates/zip.html.ep:7
msgid ""
@@ -335,7 +334,7 @@ msgstr "Meine Bilder"
#: themes/default/templates/gallery.html.ep:45
msgid "Next (arrow right)"
msgstr ""
msgstr "Nächstes (rechte Pfeiltaste)"
#: themes/default/templates/partial/myfiles.js.ep:105 themes/default/templates/partial/myfiles.js.ep:132
msgid "No limit"
@@ -386,7 +385,7 @@ msgstr ""
#: themes/default/templates/gallery.html.ep:43
msgid "Previous (arrow left)"
msgstr ""
msgstr "Vorheriges (linke Pfeiltaste)"
#: themes/default/templates/index.html.ep:46 themes/default/templates/index.html.ep:49 themes/default/templates/myfiles.html.ep:96 themes/default/templates/myfiles.html.ep:99
msgid "Random image link"
@@ -394,7 +393,7 @@ msgstr "Zufälliger Bildlink"
#: themes/default/templates/stats.html.ep:22
msgid "Raw stats"
msgstr ""
msgstr "Rohe Statistiken"
#: themes/default/templates/myfiles.html.ep:52
msgid "Save changes"
@@ -406,7 +405,7 @@ msgstr "Sende ein Bild"
#: themes/default/templates/login.html.ep:16 themes/default/templates/logout.html.ep:5 themes/default/templates/partial/navbar.html.ep:37
msgid "Signin"
msgstr "Einloggen"
msgstr "Anmelden"
#: themes/default/templates/index.html.ep:151 themes/default/templates/partial/gallery.js.ep:211 themes/default/templates/partial/lutim.js.ep:176
msgid "Something bad happened"
@@ -464,10 +463,12 @@ msgid ""
"The automatic download process will open a tab in your browser for each link."
" You need to allow popups for Lutim."
msgstr ""
"Das automatische Herunterladen wird für jeden Link einen neuen Tab in deinem "
"Browser öffnen. Du musst Pop-Ups für Lutim erlauben."
#: themes/default/templates/partial/myfiles.js.ep:32
msgid "The data has been successfully imported."
msgstr ""
msgstr "Die Daten wurden erfolgreich importiert."
#: lib/Lutim/Controller/Image.pm:160 lib/Lutim/Controller/Image.pm:228
msgid "The delete token is invalid."
@@ -518,7 +519,7 @@ msgstr "Die Zeit bis zum Löschen des Bildes wurde erfolgreich geändert"
#: themes/default/templates/partial/gallery.js.ep:277
msgid "There is XXXX image(s) in the gallery"
msgstr ""
msgstr "Es gibt XXXX Bild(er) in der Galerie"
#. ($c->config->{contact})
#: lib/Lutim/Controller/Image.pm:485
@@ -529,11 +530,11 @@ msgstr ""
#: themes/default/templates/gallery.html.ep:30
msgid "Toggle fullscreen"
msgstr ""
msgstr "Vollbild umschalten"
#: themes/default/templates/partial/navbar.html.ep:8
msgid "Toggle navigation"
msgstr ""
msgstr "Navigation umschalten"
#: lib/Lutim/Command/cron/stats.pm:162 themes/default/templates/raw.html.ep:11
msgid "Total"
@@ -621,9 +622,9 @@ msgid ""
"do it via <a href=\"https://www.tipeee.com/fiat-tux\">Tipeee</a> or via <a "
"href=\"https://liberapay.com/sky/\">Liberapay</a>."
msgstr ""
"Ja, ist es! Auf der anderen Seite kannst du den Entwickler via <a href="
"\"https://www.tipeee.com/fiat-tux\">Tipeee</a> oder <a href=\"https://"
"liberapay.com/sky/\">Liberapay</a> unterstützen."
"Ja, ist es! Jedoch kannst du den Entwickler via <a href=\"https://www.tipeee."
"com/fiat-tux\">Tipeee</a> oder <a href=\"https://liberapay.com/sky/\""
">Liberapay</a> unterstützen."
#: themes/default/templates/zip.html.ep:6
msgid "You asked to download a zip archive for too much files."
@@ -677,7 +678,7 @@ msgstr "auf"
#: themes/default/templates/about.html.ep:39
msgid "paste image to upload ability"
msgstr ""
msgstr "Bild zum Hochladen einfügen-Funktion"
#: themes/default/templates/about.html.ep:41
msgid "russian translation"
@@ -690,3 +691,21 @@ msgstr "spanische Übersetzung"
#: themes/default/templates/about.html.ep:28
msgid "webapp developer"
msgstr "Webapp-Entwickler"
#: themes/default/templates/about.html.ep:24
msgid "For more details, see the <a href=\"https://framagit.org/fiat-tux/hat-softwares/lutim\">homepage of the project</a>."
msgstr ""
"Für weitere Details besuche die <a href=\"https://framagit.org/fiat-tux/"
"hat-softwares/lutim\">Website des Projekts</a>."
#: themes/default/templates/index.html.ep:174 themes/default/templates/index.html.ep:218
msgid "Single watermark"
msgstr "Einzelnes Wasserzeichen"
#: themes/default/templates/index.html.ep:171 themes/default/templates/index.html.ep:215
msgid "Tiling watermark"
msgstr "Gekacheltes Wasserzeichen"
#: themes/default/templates/index.html.ep:177 themes/default/templates/index.html.ep:221
msgid "No watermark"
msgstr "Kein Wasserzeichen"

View File

@@ -11,8 +11,8 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
"PO-Revision-Date: 2020-03-09 16:23+0000\n"
"Last-Translator: Luc Didry <luc@framasoft.org>\n"
"PO-Revision-Date: 2021-04-24 11:14+0000\n"
"Last-Translator: Berto Te <ateira@3fpj.com>\n"
"Language-Team: Spanish <https://weblate.framasoft.org/projects/lutim/"
"default-theme/es/>\n"
"Language: es\n"
@@ -20,7 +20,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 3.11.2\n"
"X-Generator: Weblate 4.5.1\n"
#. (7)
#. (30)
@@ -646,7 +646,7 @@ msgstr "Ha sido desconectado con éxito."
#: themes/default/templates/gallery.html.ep:31
msgid "Zoom in/out"
msgstr "Zoom in/out"
msgstr "Zoom aumentar / reducir"
#: themes/default/templates/about.html.ep:27
msgid "and on"
@@ -693,3 +693,15 @@ msgid "For more details, see the <a href=\"https://framagit.org/fiat-tux/hat-sof
msgstr ""
"Para más detalles, vea la <a href=\"https://framagit.org/fiat-tux/"
"hat-softwares/lutim\">página del proyecto</a>."
#: themes/default/templates/index.html.ep:171 themes/default/templates/index.html.ep:215
msgid "Tiling watermark"
msgstr "Marca de agua en mosaico"
#: themes/default/templates/index.html.ep:174 themes/default/templates/index.html.ep:218
msgid "Single watermark"
msgstr "Marca de agua única"
#: themes/default/templates/index.html.ep:177 themes/default/templates/index.html.ep:221
msgid "No watermark"
msgstr "Sin marca de agua"

View File

@@ -0,0 +1,637 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
"PO-Revision-Date: 2022-07-24 18:36+0000\n"
"Last-Translator: Milo Ivir <mail@milotype.de>\n"
"Language-Team: Croatian <https://weblate.framasoft.org/projects/lutim/"
"default-theme/hr/>\n"
"Language: hr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 4.13.1\n"
#. (7)
#. (30)
#. ($delay)
#. (config('max_delay')
#: lib/Lutim/Command/cron/stats.pm:156 lib/Lutim/Command/cron/stats.pm:157 lib/Lutim/Command/cron/stats.pm:170 lib/Lutim/Command/cron/stats.pm:171 lib/Lutim/Command/cron/stats.pm:187 lib/Lutim/Command/cron/stats.pm:188 themes/default/templates/myfiles.html.ep:24 themes/default/templates/myfiles.html.ep:33 themes/default/templates/myfiles.html.ep:34 themes/default/templates/partial/for_my_delay.html.ep:13 themes/default/templates/partial/for_my_delay.html.ep:14 themes/default/templates/partial/for_my_delay.html.ep:4 themes/default/templates/partial/lutim.js.ep:140 themes/default/templates/partial/lutim.js.ep:149 themes/default/templates/partial/lutim.js.ep:150 themes/default/templates/partial/raw.js.ep:23 themes/default/templates/partial/raw.js.ep:24 themes/default/templates/partial/raw.js.ep:6 themes/default/templates/partial/raw.js.ep:7 themes/default/templates/raw.html.ep:8 themes/default/templates/raw.html.ep:9
msgid "%1 days"
msgstr "%1 dana"
#. ($total)
#: themes/default/templates/stats.html.ep:2
msgid "%1 sent images on this instance from beginning."
msgstr "Broj poslanih slika u ovoj instanci od početka: %1."
#: themes/default/templates/index.html.ep:228
msgid "-or-"
msgstr "-ili-"
#: lib/Lutim.pm:342 lib/Lutim/Command/cron/stats.pm:158 lib/Lutim/Command/cron/stats.pm:172 lib/Lutim/Command/cron/stats.pm:189 themes/default/templates/index.html.ep:5 themes/default/templates/myfiles.html.ep:5 themes/default/templates/partial/raw.js.ep:25 themes/default/templates/partial/raw.js.ep:8 themes/default/templates/raw.html.ep:10
msgid "1 year"
msgstr "1 godina"
#: lib/Lutim.pm:341 lib/Lutim/Command/cron/stats.pm:155 lib/Lutim/Command/cron/stats.pm:169 lib/Lutim/Command/cron/stats.pm:186 themes/default/templates/index.html.ep:4 themes/default/templates/myfiles.html.ep:33 themes/default/templates/myfiles.html.ep:4 themes/default/templates/partial/for_my_delay.html.ep:13 themes/default/templates/partial/lutim.js.ep:149 themes/default/templates/partial/raw.js.ep:22 themes/default/templates/partial/raw.js.ep:5 themes/default/templates/raw.html.ep:7
msgid "24 hours"
msgstr "24 sata"
#: themes/default/templates/partial/myfiles.js.ep:210
msgid ": Error while trying to get the counter."
msgstr ": Greška u dohvaćanju brojača."
#: themes/default/templates/partial/navbar.html.ep:63
msgid "About"
msgstr "O programu"
#: lib/Lutim/Command/cron/stats.pm:151 themes/default/templates/raw.html.ep:3
msgid "Active images"
msgstr "Aktivne slike"
#: lib/Lutim/Controller/Image.pm:329
msgid "An error occured while downloading the image."
msgstr "Dogodila se greška prilikom preuzimanja slike."
#: themes/default/templates/zip.html.ep:2
msgid "Archives download"
msgstr "Preuzimanje arhiva"
#: themes/default/templates/about.html.ep:44 themes/default/templates/myfiles.html.ep:129 themes/default/templates/stats.html.ep:25
msgid "Back to homepage"
msgstr "Natrag na web-stranicu"
#: themes/default/templates/index.html.ep:231 themes/default/templates/index.html.ep:232
msgid "Click to open the file browser"
msgstr "Pritisni za otvaranje preglednika datoteka"
#: themes/default/templates/myfiles.html.ep:51
msgid "Close"
msgstr "Zatvori"
#: themes/default/templates/gallery.html.ep:29
msgid "Close (Esc)"
msgstr "Zatvori (Esc)"
#: themes/default/templates/about.html.ep:30
msgid "Contributors"
msgstr "Doprinositelji"
#: themes/default/templates/partial/common.js.ep:113 themes/default/templates/partial/common.js.ep:93
msgid "Copied to clipboard"
msgstr "Kopirano u međuspremnik"
#: themes/default/templates/partial/lutim.js.ep:215 themes/default/templates/partial/lutim.js.ep:278 themes/default/templates/partial/lutim.js.ep:364
msgid "Copy all view links to clipboard"
msgstr "Kopiraj sve poveznice prikaza u međuspremnik"
#: themes/default/templates/index.html.ep:105 themes/default/templates/index.html.ep:16 themes/default/templates/index.html.ep:32 themes/default/templates/index.html.ep:48 themes/default/templates/index.html.ep:81 themes/default/templates/index.html.ep:89 themes/default/templates/index.html.ep:97 themes/default/templates/myfiles.html.ep:66 themes/default/templates/myfiles.html.ep:82 themes/default/templates/myfiles.html.ep:98 themes/default/templates/partial/common.js.ep:186 themes/default/templates/partial/lutim.js.ep:106 themes/default/templates/partial/lutim.js.ep:121 themes/default/templates/partial/lutim.js.ep:80 themes/default/templates/partial/lutim.js.ep:92 themes/default/templates/partial/myfiles.js.ep:172
msgid "Copy to clipboard"
msgstr "Kopiraj u međuspremnik"
#: themes/default/templates/myfiles.html.ep:117
msgid "Counter"
msgstr "Brojač"
#: themes/default/templates/stats.html.ep:18
msgid "Delay repartition chart for disabled images"
msgstr "Dijagram odgode raspodjele za isključene slike"
#: themes/default/templates/stats.html.ep:15
msgid "Delay repartition chart for enabled images"
msgstr "Dijagram odgode raspodjele za uključene slike"
#: themes/default/templates/index.html.ep:127 themes/default/templates/index.html.ep:159 themes/default/templates/index.html.ep:203 themes/default/templates/myfiles.html.ep:118 themes/default/templates/myfiles.html.ep:45 themes/default/templates/partial/lutim.js.ep:161
msgid "Delete at first view?"
msgstr "Izbrisati pri prvom prikazu?"
#: lib/Lutim/Command/cron/stats.pm:152 themes/default/templates/raw.html.ep:4
msgid "Deleted images"
msgstr "Izbrisane slike"
#: lib/Lutim/Command/cron/stats.pm:153 themes/default/templates/raw.html.ep:5
msgid "Deleted images in 30 days"
msgstr "Izbrisane slike u 30 dana"
#: themes/default/templates/index.html.ep:110 themes/default/templates/myfiles.html.ep:121 themes/default/templates/partial/common.js.ep:178 themes/default/templates/partial/common.js.ep:181
msgid "Deletion link"
msgstr "Poveznica za brisanje"
#: themes/default/templates/gallery.html.ep:10
msgid "Download all images"
msgstr "Preuzmi sve slike"
#: themes/default/templates/index.html.ep:93 themes/default/templates/index.html.ep:95 themes/default/templates/partial/lutim.js.ep:102 themes/default/templates/partial/lutim.js.ep:98
msgid "Download link"
msgstr "Poveznica za preuzimanje"
#: themes/default/templates/index.html.ep:26 themes/default/templates/index.html.ep:28 themes/default/templates/myfiles.html.ep:76 themes/default/templates/myfiles.html.ep:78
msgid "Download zip link"
msgstr "Poveznica za preuzimanje zip-a"
#: themes/default/templates/index.html.ep:227
msgid "Drag & drop images here"
msgstr "Povuci i ispusti slike ovamo"
#: themes/default/templates/about.html.ep:7
msgid "Drag and drop an image in the appropriate area or use the traditional way to send files and Lutim will provide you four URLs. One to view the image, an other to directly download it, one you can use on social networks and a last to delete the image when you want."
msgstr ""
"Povuci i ispusti sliku u odgovarajuće područje ili koristi tradicionalni "
"način slanja datoteka i Lutim će ti dati četiri URL-a. Jedan za pregled "
"slike, drugi za izravno preuzimanje, jedan koji možeš koristiti na "
"društvenim mrežama i zadnji za brisanje slike kada želiš."
#: themes/default/templates/index.html.ep:162 themes/default/templates/index.html.ep:206
msgid "Encrypt the image (Lutim does not keep the key)."
msgstr "Šifriraj sliku (Lutim ne čuva ključ)."
#: themes/default/templates/partial/lutim.js.ep:45 themes/default/templates/partial/myfiles.js.ep:128
msgid "Error while trying to modify the image."
msgstr "Greška prilikom pokušaja stvaranja promjena u slici."
#: themes/default/templates/stats.html.ep:10
msgid "Evolution of total files"
msgstr "Razvoj ukupnog broja datoteka"
#: themes/default/templates/myfiles.html.ep:120
msgid "Expires at"
msgstr "Isteče"
#: themes/default/templates/myfiles.html.ep:106
msgid "Export localStorage data"
msgstr "Izvezi podatke lokalnog spremišta"
#: themes/default/templates/myfiles.html.ep:115
msgid "File name"
msgstr "Ime datoteke"
#: themes/default/templates/about.html.ep:24
msgid "For more details, see the <a href=\"https://framagit.org/fiat-tux/hat-softwares/lutim\">homepage of the project</a>."
msgstr ""
"Pogledaj detalje na <a href=\"https://framagit.org/fiat-tux/hat-softwares/"
"lutim\">web-stranici projekta</a>."
#: themes/default/templates/partial/navbar.html.ep:66
msgid "Fork me!"
msgstr "Kopiraj granu!"
#: themes/default/templates/index.html.ep:10 themes/default/templates/index.html.ep:12 themes/default/templates/myfiles.html.ep:60 themes/default/templates/myfiles.html.ep:62
msgid "Gallery link"
msgstr "Poveznica galerije"
#: themes/default/templates/partial/common.js.ep:116 themes/default/templates/partial/common.js.ep:134
msgid "Hit Ctrl+C, then Enter to copy the short link"
msgstr "Pritisni Ctrl+C, zatim Enter za kopiranje kratke poveznice"
#: themes/default/templates/layouts/default.html.ep:47
msgid "Homepage"
msgstr "Web-stranica"
#: themes/default/templates/about.html.ep:20
msgid "How do you pronounce Lutim?"
msgstr "Kako se izgovara Lutim?"
#: themes/default/templates/about.html.ep:6
msgid "How does it work?"
msgstr "Kako radi?"
#: themes/default/templates/about.html.ep:18
msgid "How to report an image?"
msgstr "Kako prijaviti sliku?"
#: themes/default/templates/about.html.ep:14
msgid "If the files are deleted if you ask it while posting it, their SHA512 footprint are retained."
msgstr ""
"Ako se datoteke izbrišu ako to zatražiš dok ih objavljuješ, njihov SHA512 "
"otisak se zadržava."
#: themes/default/templates/index.html.ep:188 themes/default/templates/index.html.ep:241
msgid "Image URL"
msgstr "URL adresa slike"
#: lib/Lutim/Command/cron/stats.pm:150 themes/default/templates/raw.html.ep:2
msgid "Image delay"
msgstr "Kašnjenje slike"
#: themes/default/templates/partial/common.js.ep:157
msgid "Image deleted"
msgstr "Slika izbrisana"
#: lib/Lutim/Controller/Image.pm:799
msgid "Image not found."
msgstr "Slika nije pronađena."
#: themes/default/templates/myfiles.html.ep:107
msgid "Import localStorage data"
msgstr "Uvezi podatke lokalnog spremišta"
#: themes/default/templates/partial/navbar.html.ep:55
msgid "Informations"
msgstr "Informacije"
#: themes/default/templates/partial/navbar.html.ep:25
msgid "Install webapp"
msgstr "Instaliraj web-aplikaciju"
#: themes/default/templates/partial/navbar.html.ep:21
msgid "Instance's statistics"
msgstr "Statistika instance"
#: themes/default/templates/about.html.ep:11
msgid "Is it really anonymous?"
msgstr "Je li stvarno anonimno?"
#: themes/default/templates/about.html.ep:9
msgid "Is it really free (as in free beer)?"
msgstr "Je li se stvarno može besplatno koristiti?"
#: themes/default/templates/about.html.ep:21
msgid "Juste like you pronounce the French word <a href=\"https://fr.wikipedia.org/wiki/Lutin\">lutin</a> (/ly.tɛ̃/)."
msgstr ""
"Isto kao izgovaranje francuske riječi <a href=\"https://fr.wikipedia.org/"
"wiki/Lutin\">lutin</a> (/ly.tɛ̃/)."
#: themes/default/templates/index.html.ep:165 themes/default/templates/index.html.ep:209
msgid "Keep EXIF tags"
msgstr "Zadrži EXIF oznake"
#: themes/default/templates/partial/navbar.html.ep:43
msgid "Language"
msgstr "Jezik"
#: themes/default/templates/index.html.ep:130 themes/default/templates/index.html.ep:191 themes/default/templates/index.html.ep:244 themes/default/templates/partial/lutim.js.ep:165
msgid "Let's go!"
msgstr "Kreni!"
#: themes/default/templates/partial/navbar.html.ep:60
msgid "License:"
msgstr "Licenca:"
#: themes/default/templates/index.html.ep:101 themes/default/templates/index.html.ep:103 themes/default/templates/partial/lutim.js.ep:112 themes/default/templates/partial/lutim.js.ep:116
msgid "Link for share on social networks"
msgstr "Poveznica za dijeljenje na društvenim mrežama"
#: themes/default/templates/login.html.ep:8
msgid "Login"
msgstr "Prijava"
#: themes/default/templates/partial/navbar.html.ep:33
msgid "Logout"
msgstr "Odjava"
#: themes/default/templates/zip.html.ep:7
msgid "Lutim can't zip so many images at once, so it splitted your demand in multiple URLs."
msgstr ""
"Lutim ne može komprimirati toliko slika odjednom. Tvoj zahtjev je stoga "
"podijeljen na više URL-ova."
#: themes/default/templates/about.html.ep:4
msgid "Lutim is a free (as in free beer) and anonymous image hosting service. It's also the name of the free (as in free speech) software which provides this service."
msgstr ""
"Lutim je besplatna i anonimna hosting usluga za slike. To je također ime "
"slobodnog softvera koji pruža ovu uslugu."
#: themes/default/templates/about.html.ep:25
msgid "Main developers"
msgstr "Glavni programeri"
#: themes/default/templates/index.html.ep:85 themes/default/templates/index.html.ep:87 themes/default/templates/partial/lutim.js.ep:86 themes/default/templates/partial/lutim.js.ep:89
msgid "Markdown syntax"
msgstr "Markdown sintaksa"
#: themes/default/templates/partial/myfiles.js.ep:179
msgid "Modify expiration delay"
msgstr "Promijeni odgodu isteka"
#: themes/default/templates/myfiles.html.ep:7 themes/default/templates/partial/navbar.html.ep:18
msgid "My images"
msgstr "Moje slike"
#: themes/default/templates/gallery.html.ep:45
msgid "Next (arrow right)"
msgstr "Sljedeće (desna strelica)"
#: themes/default/templates/partial/myfiles.js.ep:120 themes/default/templates/partial/myfiles.js.ep:162
msgid "No limit"
msgstr "Bez ograničenja"
#: themes/default/templates/index.html.ep:177 themes/default/templates/index.html.ep:221
msgid "No watermark"
msgstr "Bez vodenog žiga"
#: themes/default/templates/index.html.ep:190 themes/default/templates/index.html.ep:236
msgid "Only images are allowed"
msgstr "Dozvoljene su samo slike"
#: themes/default/templates/myfiles.html.ep:11
msgid "Only the images sent with this browser will be listed here. The details are stored in localStorage: if you delete your localStorage data, you'll loose these details."
msgstr ""
"Ovdje će biti navedene samo slike poslane ovim preglednikom. Detalji se "
"spremaju u lokalno spremište: ako izbrišeš svoje podatke lokalnog spremišta, "
"izgubit ćeš te detalje."
#: themes/default/templates/about.html.ep:16
msgid "Only the uploader! (well, only if he's the only owner of the images' rights before the upload)"
msgstr ""
"Samo prenositelj! (zapravo, samo ako je on jedini vlasnik prava na slike "
"prije prijenosa)"
#: themes/default/templates/login.html.ep:12
msgid "Password"
msgstr "Lozinka"
#: themes/default/templates/zip.html.ep:12
msgid "Please click on each URL to download the different zip files."
msgstr "Pritisni svaki URL za preuzimanje zip datoteka."
#. (config('contact')
#: themes/default/templates/about.html.ep:19
msgid "Please contact the administrator: %1"
msgstr "Kontaktiraj administratora: %1"
#: lib/Lutim/Controller/Authent.pm:36
msgid "Please, check your credentials: unable to authenticate."
msgstr "Provjeri svoje podatke autentifikacije: autentifikacija je neuspjela."
#: themes/default/templates/gallery.html.ep:43
msgid "Previous (arrow left)"
msgstr "Prethodno (lijeva strelica)"
#: themes/default/templates/index.html.ep:42 themes/default/templates/index.html.ep:44 themes/default/templates/myfiles.html.ep:92 themes/default/templates/myfiles.html.ep:94
msgid "Random image link"
msgstr "Poveznica slučajne slike"
#: themes/default/templates/stats.html.ep:22
msgid "Raw stats"
msgstr "Neobrađena statistika"
#: themes/default/templates/myfiles.html.ep:52
msgid "Save changes"
msgstr "Spremi promjene"
#: themes/default/templates/index.html.ep:183
msgid "Send an image"
msgstr "Pošalji sliku"
#: themes/default/templates/login.html.ep:16 themes/default/templates/logout.html.ep:5 themes/default/templates/partial/navbar.html.ep:37
msgid "Signin"
msgstr "Prijava"
#: themes/default/templates/index.html.ep:174 themes/default/templates/index.html.ep:218
msgid "Single watermark"
msgstr "Jedan vodeni žig"
#: themes/default/templates/index.html.ep:145 themes/default/templates/partial/gallery.js.ep:211 themes/default/templates/partial/lutim.js.ep:176
msgid "Something bad happened"
msgstr "Dogodila se greška"
#. ($c->config('contact')
#: lib/Lutim/Controller/Image.pm:806
msgid "Something went wrong when creating the zip file. Try again later or contact the administrator (%1)."
msgstr ""
"Dogodila se greška prilikom izrade zip datoteke. Pokušaj ponovo kasnije ili "
"kontaktiraj administratora (%1)."
#: themes/default/templates/about.html.ep:13
msgid "The IP address of the image's sender is retained for a delay which depends of the administrator's choice (for the official instance, which is located in France, it's one year)."
msgstr ""
"IP adresa pošiljatelja slike zadržava se odgodom koja ovisi o izboru "
"administratora (za službenu instancu, koja se nalazi u Francuskoj, to je "
"godinu dana)."
#: themes/default/templates/about.html.ep:23
msgid "The Lutim software is a <a href=\"http://en.wikipedia.org/wiki/Free_software\">free software</a>, which allows you to download and install it on you own server. Have a look at the <a href=\"https://www.gnu.org/licenses/agpl-3.0.html\">AGPL</a> to see what you can do."
msgstr ""
"Softver Lutim je <a href=\"http://en.wikipedia.org/wiki/Free_software\""
">slobodan softver</a> koji omogućuje preuzmanje i instaliranje softvera na "
"vlastiti poslužitelj. Pogledaj <a href=\"https://www.gnu.org/licenses/agpl-3."
"0.html\">AGPL</a> za prikaz mogućnosti."
#: lib/Lutim/Controller/Image.pm:348
msgid "The URL is not valid."
msgstr "URL nije ispravan."
#: themes/default/templates/zip.html.ep:16
msgid "The automatic download process will open a tab in your browser for each link. You need to allow popups for Lutim."
msgstr ""
"Automatski postupak preuzimanja otvorit će karticu u tvom pregledniku za "
"svaku poveznicu. Moraš dozvoliti skočne prozore za Lutim."
#: themes/default/templates/partial/myfiles.js.ep:32
msgid "The data has been successfully imported."
msgstr "Podaci su uspješno uvezeni."
#: lib/Lutim/Controller/Image.pm:160 lib/Lutim/Controller/Image.pm:228
msgid "The delete token is invalid."
msgstr "Token brisanja je neispravan."
#. ($upload->filename)
#: lib/Lutim/Controller/Image.pm:531
msgid "The file %1 is not an image."
msgstr "Datoteka %1 nije slika."
#. ($tx->res->max_message_size)
#. ($c->req->max_message_size)
#. (config('max_file_size')
#: lib/Lutim/Controller/Image.pm:312 lib/Lutim/Controller/Image.pm:381 themes/default/templates/partial/lutim.js.ep:249
msgid "The file exceed the size limit (%1)"
msgstr "Datoteka je prekoračila granicu (%1)"
#: themes/default/templates/stats.html.ep:12
msgid "The graph's datas are not updated in real-time."
msgstr "Podaci dijagrama se ne aktualiziraju se u stvarnom vremenu."
#. ($image->filename)
#: lib/Lutim/Controller/Image.pm:230
msgid "The image %1 has already been deleted."
msgstr "Slika %1 je već izbrisana."
#. ($image->filename)
#: lib/Lutim/Controller/Image.pm:239 lib/Lutim/Controller/Image.pm:244
msgid "The image %1 has been successfully deleted"
msgstr "Slika %1 je uspješno izbrisana"
#: themes/default/templates/index.html.ep:57
msgid "The images are encrypted on the server (Lutim does not keep the key)."
msgstr "Slike su šifrirane na poslužitelju (Lutim ne čuva ključ)."
#: themes/default/templates/about.html.ep:5
msgid "The images you post on Lutim can be stored indefinitely or be deleted at first view or after a delay selected from those proposed."
msgstr ""
"Slike koje objeviš na Lutimu mogu se spremiti na neodređeno vrijeme ili se "
"mogu izbrisati pri prvom pregledu ili nakon odabrane odgode od predloženih."
#: lib/Lutim/Controller/Image.pm:168
msgid "The images delay has been successfully modified"
msgstr "Kašnjenje slike je uspješno promijenjeno"
#: themes/default/templates/partial/gallery.js.ep:277
msgid "There is XXXX image(s) in the gallery"
msgstr "Galerija sadrži XXXX slika"
#. ($c->config->{contact})
#: lib/Lutim/Controller/Image.pm:528
msgid "There is no more available URL. Retry or contact the administrator. %1"
msgstr ""
"Nema više dostupnog URL-a. Pokušaj ponovo ili kontaktiraj administratora. %1"
#: themes/default/templates/index.html.ep:171 themes/default/templates/index.html.ep:215
msgid "Tiling watermark"
msgstr "Pločasti vodeni žig"
#: themes/default/templates/gallery.html.ep:30
msgid "Toggle fullscreen"
msgstr "Uključi/isključi cjeloekranski prikaz"
#: themes/default/templates/partial/navbar.html.ep:8
msgid "Toggle navigation"
msgstr "Uključi/isključi navigaciju"
#: lib/Lutim/Command/cron/stats.pm:159 themes/default/templates/raw.html.ep:11
msgid "Total"
msgstr "Ukupno"
#: themes/default/templates/index.html.ep:72 themes/default/templates/partial/lutim.js.ep:17
msgid "Tweet it!"
msgstr "Pošalji tweet!"
#: themes/default/templates/partial/common.js.ep:110 themes/default/templates/partial/common.js.ep:90
msgid "Unable to copy to clipboard"
msgstr "Neuspjelo kopiranje u međuspremink"
#. ($short)
#: lib/Lutim/Controller/Image.pm:108 lib/Lutim/Controller/Image.pm:202 lib/Lutim/Controller/Image.pm:273
msgid "Unable to find the image %1."
msgstr "Neuspjelo pronalaženje slike %1."
#: lib/Lutim/Controller/Image.pm:617 lib/Lutim/Controller/Image.pm:662 lib/Lutim/Controller/Image.pm:703 lib/Lutim/Controller/Image.pm:746 lib/Lutim/Controller/Image.pm:758 lib/Lutim/Controller/Image.pm:769 lib/Lutim/Controller/Image.pm:796 lib/Lutim/Plugin/Helpers.pm:89
msgid "Unable to find the image: it has been deleted."
msgstr "Neuspjelo pronalaženje slike: slika je izbrisana."
#: lib/Lutim/Controller/Image.pm:145
msgid "Unable to get counter"
msgstr "Neuspjelo dohvaćanje brojača"
#: themes/default/templates/about.html.ep:17
msgid "Unlike many image sharing services, you don't give us rights on uploaded images."
msgstr ""
"Za razliku od mnogih usluga za dijeljenje slika, ne daješ nam prava za "
"prenesene slike."
#: themes/default/templates/index.html.ep:187 themes/default/templates/index.html.ep:239
msgid "Upload an image with its URL"
msgstr "Prenesi sliku s ovim URL-om"
#: themes/default/templates/myfiles.html.ep:119
msgid "Uploaded at"
msgstr "Preneseno"
#: themes/default/templates/stats.html.ep:6
msgid "Uploaded files by days"
msgstr "Prenesene datoteke po danima"
#. ($c->app->config('contact')
#: lib/Lutim/Plugin/Helpers.pm:222
msgid "Uploading is currently disabled, please try later or contact the administrator (%1)."
msgstr ""
"Prijenos je trenutačno onemogućen, pokušaj kasnije ili kontaktiraj "
"administratora (%1)."
#: themes/default/templates/index.html.ep:77 themes/default/templates/index.html.ep:79 themes/default/templates/myfiles.html.ep:116 themes/default/templates/partial/lutim.js.ep:72 themes/default/templates/partial/lutim.js.ep:76
msgid "View link"
msgstr "Pogledaj poveznicu"
#: themes/default/templates/about.html.ep:22
msgid "What about the software which provides the service?"
msgstr "Što je sa softverom koji pruža uslugu?"
#: themes/default/templates/about.html.ep:3
msgid "What is Lutim?"
msgstr "Što je Lutim?"
#: themes/default/templates/about.html.ep:15
msgid "Who owns rights on images uploaded on Lutim?"
msgstr "Tko posjeduje prava nad slikama postavljene na Lutimu?"
#: themes/default/templates/about.html.ep:12
msgid "Yes, it is! On the other side, for legal reasons, your IP address will be stored when you send an image. Don't panic, it is normally the case of all sites on which you send files!"
msgstr ""
"Da, je! Međutim, iz pravnih razloga, tvoja IP adresa će se spremiti kada "
"pošalješ sliku. Bez panike, to je normalno za sve stranice na koje šalješ "
"datoteke!"
#: themes/default/templates/about.html.ep:10
msgid "Yes, it is! On the other side, if you want to support the developer, you can do it via <a href=\"https://www.tipeee.com/fiat-tux\">Tipeee</a> or via <a href=\"https://liberapay.com/sky/\">Liberapay</a>."
msgstr ""
"Da, je! Međutim, ako želiš podržati programera, to možete učiniti putem "
"usluge <a href=\"https://www.tipeee.com/fiat-tux\">Tipeee</a> ili <a href=\" "
"https://liberapay.com/sky/\">Liberapay</a>."
#: themes/default/templates/zip.html.ep:6
msgid "You asked to download a zip archive for too much files."
msgstr "Zatražio/la si preuzimanje zip arhive za previše datoteka."
#: themes/default/templates/about.html.ep:8
msgid "You can, optionally, request that the image(s) posted on Lutim to be deleted at first view (or download) or after the delay selected from those proposed."
msgstr ""
"Opcionalno možeš zatražiti da se objavljene slike na Lutimu izbrišu pri "
"prvom pregledu (ili preuzimanju) ili nakon odabrane odgode od predloženih."
#: lib/Lutim/Controller/Authent.pm:27
msgid "You have been successfully logged in."
msgstr "Uspješno si prijavljan/a."
#: lib/Lutim/Controller/Authent.pm:66 themes/default/templates/logout.html.ep:3
msgid "You have been successfully logged out."
msgstr "Uspješno si odjevljen/a."
#: themes/default/templates/gallery.html.ep:31
msgid "Zoom in/out"
msgstr "Uvećaj/Umanji prikaz"
#: themes/default/templates/about.html.ep:27
msgid "and on"
msgstr "i na"
#: themes/default/templates/about.html.ep:40
msgid "arabic translation"
msgstr "prijevod na arapski"
#: themes/default/templates/about.html.ep:27
msgid "core developer"
msgstr "izvorni programer"
#: lib/Lutim.pm:340 lib/Lutim/Command/cron/stats.pm:154 lib/Lutim/Command/cron/stats.pm:168 lib/Lutim/Command/cron/stats.pm:185 themes/default/templates/index.html.ep:3 themes/default/templates/myfiles.html.ep:3 themes/default/templates/partial/raw.js.ep:21 themes/default/templates/partial/raw.js.ep:4 themes/default/templates/raw.html.ep:6
msgid "no time limit"
msgstr "bez vremenskog ograničenja"
#: themes/default/templates/about.html.ep:38
msgid "occitan translation"
msgstr "prijevod na okcitanski"
#: themes/default/templates/about.html.ep:27
msgid "on"
msgstr "na"
#: themes/default/templates/about.html.ep:39
msgid "paste image to upload ability"
msgstr "umetni sliku za mogućnost prijenosa"
#: themes/default/templates/about.html.ep:41
msgid "russian translation"
msgstr "prijevod na ruski"
#: themes/default/templates/about.html.ep:36
msgid "spanish translation"
msgstr "prijevod na španjolski"
#: themes/default/templates/about.html.ep:28
msgid "webapp developer"
msgstr "programer web-aplikacije"

View File

@@ -4,8 +4,8 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
"PO-Revision-Date: 2020-10-11 23:59+0000\n"
"Last-Translator: Валентин Бородко <valya.spaces@gmail.com>\n"
"PO-Revision-Date: 2022-12-15 21:38+0000\n"
"Last-Translator: Дмитрий Кузнецов <dk65536@gmail.com>\n"
"Language-Team: Russian <https://weblate.framasoft.org/projects/lutim/"
"default-theme/ru/>\n"
"Language: ru\n"
@@ -14,7 +14,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 4.1\n"
"X-Generator: Weblate 4.14.1\n"
#. (7)
#. (30)
@@ -182,9 +182,8 @@ msgstr ""
"lutim\">главную страницу проекта</a>."
#: themes/default/templates/partial/navbar.html.ep:80
#, fuzzy
msgid "Fork me!"
msgstr "Выложить меня!"
msgstr "Форкни меня!"
#: themes/default/templates/index.html.ep:10 themes/default/templates/index.html.ep:13 themes/default/templates/myfiles.html.ep:60 themes/default/templates/myfiles.html.ep:63
msgid "Gallery link"

View File

@@ -147,7 +147,7 @@ function delImage(e) {
url: '<%= url_for('/') %>d/'+short+'/'+token,
method: 'GET',
data: {
format: 'json'
_format: 'json'
},
success: function(data) {
if (data.success) {

2
themes/korrigan/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
public/packed/
templates/data.html.ep

35
themes/korrigan/Makefile Normal file
View File

@@ -0,0 +1,35 @@
EN=lib/Lutim/I18N/en.po
FR=lib/Lutim/I18N/fr.po
DE=lib/Lutim/I18N/de.po
ES=lib/Lutim/I18N/es.po
OC=lib/Lutim/I18N/oc.po
AR=lib/Lutim/I18N/ar.po
SEDOPTS=-e "s@SOME DESCRIPTIVE TITLE@Lutim language file@" \
-e "s@YEAR THE PACKAGE'S COPYRIGHT HOLDER@2015 Luc Didry@" \
-e "s@CHARSET@utf8@" \
-e "s@the PACKAGE package@the Lutim package@" \
-e '/^\#\. (/{N;/\n\#\. (/{N;/\n.*\.\.\/default\//{s/\#\..*\n.*\#\./\#. (/g}}}' \
-e '/^\#\. (/{N;/\n.*\.\.\/default\//{s/\n/ /}}'
SEDOPTS2=-e '/^\#.*\.\.\/default\//,+3d'
XGETTEXT=carton exec ../../local/bin/xgettext.pl
CARTON=carton exec
locales:
$(XGETTEXT) -D templates -D ../default/templates -o $(EN) 2>/dev/null
$(XGETTEXT) -D templates -D ../default/templates -o $(FR) 2>/dev/null
$(XGETTEXT) -D templates -D ../default/templates -o $(DE) 2>/dev/null
$(XGETTEXT) -D templates -D ../default/templates -o $(ES) 2>/dev/null
$(XGETTEXT) -D templates -D ../default/templates -o $(OC) 2>/dev/null
$(XGETTEXT) -D templates -D ../default/templates -o $(AR) 2>/dev/null
sed $(SEDOPTS) -i $(EN)
sed $(SEDOPTS2) -i $(EN)
sed $(SEDOPTS) -i $(FR)
sed $(SEDOPTS2) -i $(FR)
sed $(SEDOPTS) -i $(DE)
sed $(SEDOPTS2) -i $(DE)
sed $(SEDOPTS) -i $(ES)
sed $(SEDOPTS2) -i $(ES)
sed $(SEDOPTS) -i $(OC)
sed $(SEDOPTS) -i $(OC)
sed $(SEDOPTS2) -i $(AR)
sed $(SEDOPTS2) -i $(AR)

17
themes/korrigan/Readme.md Normal file
View File

@@ -0,0 +1,17 @@
I know there is a lot to work on but this fits my needs for now and don't have much time to rework the theme from beginning.
Feel free to open a merge request for improvements.
![preview of the theme](./preview.png)
# Credits:
* Triskel image comes from https://upload.wikimedia.org/wikipedia/commons/0/07/Triskele-Symbol-spiral-five-thirds-turns.svg
# License:
[MIT](https://opensource.org/licenses/MIT)
# Author:
[nicofrand](https://nicofrand.eu) ([Twitter](https://twitter.com/@nicofrand), [Mastodon](https://mastodon.social/@nicofrand))

View File

@@ -0,0 +1,22 @@
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lutim::I18N;
use base 'Locale::Maketext';
use File::Basename qw/dirname/;
use Locale::Maketext::Lexicon {
_auto => 1,
_decode => 1,
_style => 'gettext',
'*' => [
Gettext => dirname(__FILE__) . '/I18N/*.po',
Gettext => $app_dir . 'themes/default/lib/Lutim/I18N/*.po',
]
};
use vars qw($app_dir);
BEGIN {
use Cwd;
my $app_dir = getcwd;
}
1;

BIN
themes/korrigan/preview.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

View File

@@ -0,0 +1,178 @@
/* Yeched'mad CSS */
:root {
--theme-blue: #0060DF;
--theme-blue-hover: #45A1FF;
}
body {
position: relative;
background-color: #EEEEEE;
background-size: cover;
min-height: 100vh;
display: flex;
flex-direction: column;
}
body::before,
body::after {
content: "";
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
z-index: -1;
}
body::before {
background-size: cover;
background-image: url("../img/background.svg");
}
body::after {
background: linear-gradient(to bottom, rgba(255, 255, 255, 0.75) 4em, transparent 4em);
}
body .navbar-default {
background-color: transparent;
border-color: transparent;
}
body .navbar-default .open > a,
body .navbar-default .open > a:focus,
body .navbar-default .open > a:hover,
body .navbar-default .open > a:active {
background-color: rgba(11, 103, 183, 0.5);
}
body > .container {
flex-grow: 1;
background-color: #FFFFFF;
padding: 3em;
border-radius: 5px;
box-shadow: 1px 1px 5px #333333;
display: flex;
justify-content: space-between;
font-size: 1.15em;
/* SVG coming from https://upload.wikimedia.org/wikipedia/commons/0/07/Triskele-Symbol-spiral-five-thirds-turns.svg */
background-image: url('../img/triskel.svg');
background-size: 500px;
background-repeat: no-repeat;
background-position: -125px calc(100% + 150px);
}
body > .container .upload-info {
width: 100%;
}
body > .container::before,
body > .container::after {
display: none;
}
body.index > .container > * {
background-color: rgba(255, 255, 255, 0.8);
width: calc(50% - 2em);
border-bottom-left-radius: inherit;
border-bottom-right-radius: inherit;
}
body .logo {
display: none;
}
body .header {
margin-bottom: 2em;
}
body .hennypenny {
color: var(--theme-blue);
margin-top: 0;
font-family: sans-serif;
}
body label {
font-weight: normal;
display: block;
margin: 1em 0;
}
body input[type='checkbox'] {
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
position: static;
margin: 0;
cursor: pointer;
vertical-align: middle;
display: inline-flex;
justify-content: flex-start;
align-items: center;
background-color: #555555;
width: 3rem;
height: 1.5rem;
margin-top: 0.25em;
margin-bottom: 0.25em;
border: none;
border-radius: 1em;
}
body input[type='checkbox']:checked {
color: #FFFFFF;
background-color: var(--theme-blue);
justify-content: flex-end;
}
body input[type='checkbox']::after {
content: '';
margin: 0 0.15rem;
width: 1.2rem;
height: 1.2rem;
border-radius: 50%;
background-color: white;
}
body .uploader-container {
display: flex;
flex-direction: column;
}
body .uploader {
display: flex;
flex-direction: column;
justify-content: center;
flex-grow: 1;
border: 2px dashed #DDDDDD;
border-radius: 5px;
color: #6F7986;
}
body .uploader:hover {
background-color: #FDFEFF;
}
body .uploader div.browser label {
background-color: var(--theme-blue);
}
body .uploader-container form .label {
display: block;
}
body .btn {
background-color: var(--theme-blue);
color: white;
padding: 0.5em;
}
body .btn:hover,
body .btn:focus,
body .btn:active {
background-color: var(--theme-blue-hover);
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 39 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,251 @@
% # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab:
% my %d = (
% delay_0 => l('no time limit'),
% delay_1 => l('24 hours'),
% delay_365 => l('1 year')
% );
<div id="gallery-url" class="hidden row">
<form class="form col-sm-12">
<div class="form-group">
<label for="gallery-url-input"><%= l('Gallery link') %></label>
<div class="input-group">
<a class="input-group-addon" id="gallery-url-link" href="#" target="_blank" title="<%= l('Gallery link') %>">
<span class="icon icon-picture"></span>
</a>
<input class="form-control" name="gallery-url-input" type="text" id="gallery-url-input" readonly></input>
<a href="#" class="input-group-addon jsonly copy-to-clipboard-link" title="<%= l('Copy to clipboard') %>">
<span class="icon icon-clipboard"></span>
</a>
</div>
</div>
</form>
</div>
<div id="zip-url" class="hidden row">
<form class="form col-sm-12">
<div class="form-group">
<label for="zip-url-input"><%= l('Download zip link') %></label>
<div class="input-group">
<a class="input-group-addon" id="zip-url-link" href="#" target="_blank" title="<%= l('Download zip link') %>">
<span class="icon icon-file-archive"></span>
</a>
<input class="form-control" name="zip-url-input" type="text" id="zip-url-input" readonly></input>
<a href="#" class="input-group-addon jsonly copy-to-clipboard-link" title="<%= l('Copy to clipboard') %>">
<span class="icon icon-clipboard"></span>
</a>
</div>
</div>
</form>
</div>
<div id="random-url" class="hidden row">
<form class="form col-sm-12">
<div class="form-group">
<label for="random-url-input"><%= l('Random image link') %></label>
<div class="input-group">
<a class="input-group-addon" id="random-url-link" href="#" target="_blank" title="<%= l('Random image link') %>">
<span class="icon icon-shuffle"></span>
</a>
<input class="form-control" name="random-url-input" type="text" id="random-url-input" readonly></input>
<a href="#" class="input-group-addon jsonly copy-to-clipboard-link" title="<%= l('Copy to clipboard') %>">
<span class="icon icon-clipboard"></span>
</a>
</div>
</div>
</form>
</div>
<div class="messages">
% if (config('always_encrypt')) {
<p><%= l('The images are encrypted on the server (Lutim does not keep the key).') %></p>
% }
% if (defined(stash('short'))) {
% my $url = url_for('/'.stash('short'))->to_abs();
<div class="alert alert-success">
<div>
% if (defined(stash('thumb'))) {
<div class="preview">
<a href="<%= $url.'.'.stash('ext') %>" target="_blank"><img class="thumbnail img-responsive" alt="<%= stash('filename') %> thumbnail" src="<%= stash('thumb') %>"></a>
</div>
% }
<div>
% # Display image informations
<h4>
<a href="<%= $url.'.'.stash('ext') %>" target="_blank"><%= stash('filename') %></a>
&nbsp;&nbsp;&nbsp;<a title="<%= l('Tweet it!') %>" target="_blank" href="https://twitter.com/share?url=<%= $url %>?t"><span class="icon icon-twitter"></span></a>
</h4>
% my $delete_url = url_for('delete', {short => stash('real_short'), token => stash('token')})->to_abs();
<form class="form">
<div class="form-group">
<label class="sr-only" for="view"><%= l('View link') %></label>
<div class="input-group">
<div class="input-group-addon"><a href="<%= $url.'.'.stash('ext') %>" target="_blank"><span class="icon icon-eye" title =" <%= l('View link') %>"></span></a></div>
<input type="text" class="form-control" id="view" value="<%= $url.'.'.stash('ext') %>" readonly>
<a href="#" class="input-group-addon jsonly copy-to-clipboard-link" title="<%= l('Copy to clipboard') %>"><span class="icon icon-clipboard"></span></a>
</div>
</div>
<div class="form-group">
<label class="sr-only" for="markdown"><%= l('Markdown syntax') %></label>
<div class="input-group">
<div class="input-group-addon"><span class="markdown-mark-solid" title ="<%= l('Markdown syntax') %>"></span></div>
<input type="text" class="form-control" id="markdown" value="![](<%= $url %>)" readonly>
<a href="#" class="input-group-addon jsonly copy-to-clipboard-link" title="<%= l('Copy to clipboard') %>"><span class="icon icon-clipboard"></span></a>
</div>
</div>
<div class="form-group">
<label class="sr-only" for="download"><%= l('Download link') %></label>
<div class="input-group">
<div class="input-group-addon"><a href="<%= $url %>?dl"><span class="icon icon-download" title ="<%= l('Download link') %>"></span></a></div>
<input type="text" class="form-control" id="download" value="<%= $url %>?dl" readonly>
<a href="#" class="input-group-addon jsonly copy-to-clipboard-link" title="<%= l('Copy to clipboard') %>"><span class="icon icon-clipboard"></span></a>
</div>
</div>
<div class="form-group">
<label class="sr-only" for="share"><%= l('Link for share on social networks') %></label>
<div class="input-group">
<div class="input-group-addon"><a href="<%= $url %>?t" target="_blank"><span class="icon icon-share" title ="<%= l('Link for share on social networks') %>"></span></a></div>
<input type="text" class="form-control" id="share" value="<%= $url %>?t" readonly>
<a href="#" class="input-group-addon jsonly copy-to-clipboard-link" title="<%= l('Copy to clipboard') %>"><span class="icon icon-clipboard"></span></a>
</div>
</div>
<div class="form-group">
<div class="input-group">
<span class="form-control-static"><%= link_to $delete_url => ( class => "btn btn-default col-xs-12 text-left", title => l('Deletion link') ) => begin %><span class="icon icon-trash"></span> <%= $delete_url %> <%= end %></span>
</div>
</div>
</form>
</div>
</div>
<div class="row">
% # Delay modification form
% my $modify_url = url_for('modify', {short => stash('real_short'), token => stash('token')})->to_abs();
<form class="form col-sm-11 col-sm-offset-1" method="POST" action="<%== $modify_url %>">
<div class="form-group form-inline">
<input name="image_url" type="hidden" value="<%= $url %>">
<select name="delete-day" class="form-control">
%= include 'partial/for_my_delay', d => \%d
</select>
<div class="">
<label>
<input type="checkbox" name="first-view"> <%= l('Delete at first view?') %>
</label>
</div>
<%= submit_button l('Let\'s go!'), class => 'btn btn-sm btn-default btn-primary', id => 'submitmodbutton' %>
</div>
</form>
</div>
</div>
% }
% if (defined(flash('success'))) {
<div class="alert alert-success">
<button type="button" class="close jsonly" data-dismiss="alert" aria-hidden="true">&times;</button>
<p><%== flash('success') %></p>
</div>
% }
% if (defined(flash('msg'))) {
<div class="alert alert-danger">
<button type="button" class="close jsonly" data-dismiss="alert" aria-hidden="true">&times;</button>
<strong><%= l('Something bad happened') %></strong><br>
<%= flash('filename') %> <%= flash('msg') %>
</div>
% }
</div>
<noscript>
<form class="form" method="POST" action="<%= url_for('/') %>" enctype="multipart/form-data">
<div class="form-group form-inline">
<select name="delete-day" class="form-control">
%= include 'partial/for_my_delay', d => \%d
</select>
<div class="">
<label>
<input type="checkbox" name="first-view"> <%= l('Delete at first view?') %>
</label>
<label <%== (config('always_encrypt')) ? 'class="always-encrypt"' : '' %>>
<input type="checkbox" name="crypt"> <%= l('Encrypt the image (Lutim does not keep the key).') %>
</label>
<label>
<input type="checkbox" name="keep-exif"> <%= l('Keep EXIF tags') %>
</label>
</div>
% if ($c->config('watermark_path') && $c->config('watermark_enforce') eq 'none') {
<select name="watermark" class="form-control">
<option value="tiling" <%== is_wm_selected('tiling') %>>
<%= l('Tiling watermark') %>
</option>
<option value="single" <%== is_wm_selected('single') %>>
<%= l('Single watermark') %>
</option>
<option value="none" <%== is_wm_selected('none') %>>
<%= l('No watermark') %>
</option>
</select>
% }
</div>
<div class="form-group">
<label for="lutim-file"><%= l('Send an image') %></label>
<input type="file" name="file" id="lutim-file" accept="image/*">
</div>
<div class="form-group">
<label for="lutim-file-url"><%= l('Upload an image with its URL') %></label>
<input type="url" name="lutim-file-url" placeholder="<%= l('Image URL') %>">
</div>
<p class="help-block"><%= l('Only images are allowed') %></p>
<%= submit_button l('Let\'s go!'), class => 'btn btn-default btn-primary', id => 'submitbutton' %>
</form>
</noscript>
<!-- D&D Zone-->
<div class="jsonly">
<select id="delete-day" class="form-control">
%= include 'partial/for_my_delay', d => \%d
</select>
<div class="">
<label>
<input type="checkbox" id="first-view"> <%= l('Delete at first view?') %>
</label>
<label <%== (config('always_encrypt')) ? 'class="always-encrypt"' : '' %>>
<input type="checkbox" id="crypt"> <%= l('Encrypt the image (Lutim does not keep the key).') %>
</label>
<label>
<input type="checkbox" id="keep-exif"> <%= l('Keep EXIF tags') %>
</label>
</div>
% if ($c->config('watermark_path') && $c->config('watermark_enforce') eq 'none') {
<select id="watermark" class="form-control">
<option value="tiling" <%== is_wm_selected('tiling') %>>
<%= l('Tiling watermark') %>
</option>
<option value="single" <%== is_wm_selected('single') %>>
<%= l('Single watermark') %>
</option>
<option value="none" <%== is_wm_selected('none') %>>
<%= l('No watermark') %>
</option>
</select>
% }
</div>
</div><!-- Warning: beings in default.html.ep -->
<div class="jsonly uploader-container">
<div id="drag-and-drop-zone" class="uploader">
<div><%= l('Drag & drop images here') %></div>
<div class="or"><%= l('-or-') %></div>
<div class="browser">
<label class="btn">
<span><%= l('Click to open the file browser') %></span>
<input type="file" name="files[]" multiple="multiple" title='<%= l('Click to open the file browser') %>' accept="image/*">
</label>
</div>
</div>
<p class="help-block"><%= l('Only images are allowed') %></p>
<form class="form-horizontal" method="POST" action="<%== url_for('add') %>">
<p>
<span class="hidden-spin spin"> <span class="icon-spinner animate-spin pull-right"></span></span>
<label for="lutim-file-url"><%= l('Upload an image with its URL') %></label>
<input type="url" name="lutim-file-url" class="form-control" id="lutim-file-url" placeholder="<%= l('Image URL') %>">
</p>
<a href="#" class="btn pull-right" id="file-url-button"><%= l('Let\'s go!') %></a>
</form>
</div>
</div>
<!-- /D&D Zone -->

View File

@@ -0,0 +1,98 @@
% # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab:
% use Mojo::Util qw(url_escape);
% my $twitter_url = 'https://twitter.com/share';
% my $url = url_for('/')->to_abs();
% $twitter_url .= '?url='.url_escape("$url")
% .'&text=Check out this %23Lutim instance! ';
<!DOCTYPE html>
<html>
<head>
<title>Lutim</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="utf-8" />
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link rel="icon" type="image/png" href="<%= url_for('/img/favicon.png') %>">
<link rel="icon" sizes="128x128" href="<%= url_for('/img/lutim128.png') %>">
<link rel="icon" sizes="196x196" href="<%= url_for('/img/lutim196.png') %>">
<link rel="apple-touch-icon" href="<%= url_for('/img/lutim60.png') %>">
<link rel="apple-touch-icon" sizes="76x76" href="<%= url_for('/img/lutim76.png') %>">
<link rel="apple-touch-icon" sizes="120x120" href="<%= url_for('/img/lutim120.png') %>">
<link rel="apple-touch-icon" sizes="152x152" href="<%= url_for('/img/lutim152.png') %>">
<link rel="apple-touch-icon-precomposed" sizes="128x128" href="<%= url_for('/img/lutim128.png') %>">
%= stylesheet '/css/common.min.css'
% if (current_route 'stats') {
%= stylesheet '/css/morris-0.5.1.min.css'
% } else {
%= stylesheet '/css/not_stats.min.css'
% }
% if (current_route 'gallery') {
%= stylesheet '/css/gallery.min.css'
% }
%= stylesheet '/css/korrigan.css'
</head>
<body class="<%== current_route %>">
%= include 'partial/navbar', twitter_url => $twitter_url
<div class="container">
<div class="upload-info"><!-- Warning: ends in index.html.ep -->
<div>
% if (defined(config('hosted_by'))) {
<div class="pull-right">
<%== config('hosted_by') %>
</div>
% }
<div class="header">
<div class="pull-left hidden-xs logo">
<img src="<%= url_for('/img/Lutim_small.png') %>" alt="Lutim logo" width="57" height="75">
</div>
<a class="link_nocol" href="<%= url_for('/') %>" title="<%= l('Homepage') %>"><h1 class="hennypenny">Let's Upload That Image!</h1></a>
</div>
</div>
% if (defined(config('broadcast_message'))) {
<div class="alert alert-info">
<strong><%== config('broadcast_message') %></strong>
</div>
% }
% if (defined(stash('stop_upload'))) {
<div class="alert alert-danger">
<strong><%= stash('stop_upload') %></strong>
</div>
% }
<%= content %>
</div>
% if (defined(config('piwik_img'))) {
<img src="<%== config('piwik_img') %>" class="border-zero" alt="">
% }
%= javascript '/js/jquery-3.2.1.min.js'
%= javascript '/partial/manifest.js'
%= javascript '/js/toastify.js'
%= javascript '/js/bootstrap.min.js'
%= javascript '/partial/common.js'
% if (current_route 'stats') {
%= javascript '/js/lutim.js'
%= javascript '/js/raphael-min.js'
%= javascript '/js/morris-0.5.1.min.js'
%= javascript '/js/stats.js'
%= javascript '/partial/raw.js'
% } elsif (!(current_route 'about')) {
%= javascript '/js/lutim.js'
%= javascript '/js/dmuploader.min.js'
% }
% if (current_route 'index') {
%= javascript '/partial/lutim.js'
% }
% if (current_route 'gallery') {
%= javascript '/js/photoswipe.min.js'
%= javascript '/js/photoswipe-ui-default.min.js'
%= javascript '/js/jszip.min.js'
%= javascript '/js/FileSaver.min.js'
%= javascript '/partial/gallery.js'
%= javascript '/partial/lutim.js'
% }
% if (current_route 'myfiles') {
%= javascript '/js/moment-with-locales.min.js'
%= javascript '/partial/myfiles.js'
% }
</body>
</html>

View File

@@ -0,0 +1,494 @@
% # vim:set sw=4 ts=4 sts=4 ft=javascript expandtab:
function selectInput() {
$(this).select();
}
function cleanName(name, empty) {
if (typeof(name) === 'undefined') {
return name;
}
if (empty !== undefined && empty !== null && empty) {
return name.replace(/&(l|g)t;/g, '').replace(/"/g, '\'');
} else {
return name.replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
}
function tw_url(url) {
return btn = [
'<a title="<%= l('Tweet it!') %>" target="_blank" href="https://twitter.com/share?url=<%== url_for('/')->to_abs() %>', url, '?t" class="btn btn-default">',
'<span class="icon icon-twitter"></span>',
'</a>'
].join('');
}
function modifyImage(e) {
e.preventDefault();
var url = $(this).data('modlink');
var short = $(this).data('modshort');
modify(url, short);
}
function modify(url, short) {
var limit = $('#day-'+short).val();
var del_at_view = ($('#first-view-'+short).prop('checked')) ? 1 : 0;
$.ajax({
url : url,
type : 'POST',
data : {
'image_url' : '<%== url_for('/')->to_abs() %>'+short,
'format' : 'json',
'delete-day' : limit,
'first-view' : del_at_view
},
success: function(data) {
updateItem(short, limit, del_at_view);
goodToast(data.msg);
},
error: function() {
badToast('<%= l('Error while trying to modify the image.') %>');
}
});
}
function buildMessage(success, msg) {
if(success) {
var s_url = link([msg.short, '.', msg.ext].join(''), '');
var thumb = (msg.thumb !== null) ? [
'<div class="preview">',
'<a href="', s_url, '" target="_blank">',
'<img class="thumbnail img-responsive" alt="', cleanName(msg.filename, true), ' thumbnail" src="', msg.thumb, '">',
'</a>',
'</div>'
].join('') : ''
return [
'<div class="alert alert-success" id="alert-', msg.real_short, '">',
'<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>',
'<div>', thumb,
'<div>',
'<h4>',
'<a href="', s_url, '" target="_blank">',
msg.filename,
'</a>',
'</h4>',
'<form class="form">',
'<div class="form-group">',
'<label class="sr-only" for="view', msg.real_short, '"><%= l('View link') %></label>',
'<div class="input-group input-group-sm">',
'<div class="input-group-btn adjust-addon">',
'<a href="', s_url, '" target="_blank" class="btn btn-default">',
'<span class="icon icon-eye" title=" <%= l('View link') %>"></span>',
'</a>',
'</div>',
'<input type="text" class="form-control view-link-input" id="view', msg.real_short, '" value="', s_url, '" readonly>',
'<a href="#" class="input-group-addon copy-to-clipboard-link" title="<%= l('Copy to clipboard') %>">',
'<span class="icon icon-clipboard"></span>',
'</a>',
'</div>',
'</div>',
'<div class="form-group">',
'<label class="sr-only" for="markdown', msg.real_short, '"><%= l('Markdown syntax') %></label>',
'<div class="input-group input-group-sm">',
'<div class="input-group-addon adjust-addon">',
'<span class="markdown-mark-solid" title="<%= l('Markdown syntax') %>"></span>',
'</div>',
'<input type="text" class="form-control" id="markdown', msg.real_short, '" value="![](', link(msg.short, ''), ')" readonly>',
'<a href="#" class="input-group-addon copy-to-clipboard-link" title="<%= l('Copy to clipboard') %>">',
'<span class="icon icon-clipboard"></span>',
'</a>',
'</div>',
'</div>',
'<div class="form-group">',
'<label class="sr-only" for="download', msg.real_short, '"><%= l('Download link') %></label>',
'<div class="input-group input-group-sm">',
'<div class="input-group-btn adjust-addon">',
'<a href="', link(msg.short, 'dl'), '" class="btn btn-default">',
'<span class="icon icon-download" title="<%= l('Download link') %>"></span>',
'</a>',
'</div>',
'<input type="text" class="form-control" id="download', msg.real_short, '" value="', link(msg.short, 'dl'), '" readonly>',
'<a href="#" class="input-group-addon copy-to-clipboard-link" title="<%= l('Copy to clipboard') %>">',
'<span class="icon icon-clipboard"></span>',
'</a>',
'</div>',
'</div>',
'<div class="form-group">',
'<label class="sr-only" for="share', msg.real_short, '"><%= l('Link for share on social networks') %></label>',
'<div class="input-group input-group-sm">',
'<div class="input-group-btn adjust-addon">',
'<a href="', link(msg.short, 't'), '" target="_blank" class="btn btn-default">',
'<span class="icon icon-share" title="<%= l('Link for share on social networks') %>"></span>',
'</a>',
tw_url(msg.short),
'</div>',
'<input type="text" class="form-control" id="share', msg.real_short, '" value="', link(msg.short, 't'), '" readonly>',
'<a href="#" class="input-group-addon copy-to-clipboard-link" title="<%= l('Copy to clipboard') %>">',
'<span class="icon icon-clipboard"></span>',
'</a>',
'</div>',
'</div>',
'<div class="form-group">',
'<div class="input-group">',
'<span class="form-control-static">', link(msg.real_short, '', msg.token), '</span>',
'</div>',
'</div>',
'</form>',
'</div>',
'</div>',
'<div class="row">',
'<form class="form col-sm-11 col-sm-offset-1" role="form" method="POST" action="', link(msg.real_short, '', msg.token, true), '">',
'<div class="form-group form-inline">',
'<select id="day-', msg.real_short, '" name="delete-day" class="form-control">',
% my @delays = split(',', $self->config('proposed_delays'));
% for my $delay (@delays) {
% my $text = (defined($d->{'delay_'.$delay})) ? $d->{'delay_'.$delay} : l('%1 days', $delay);
% if (config('max_delay')) {
% if ($delay) {
% if ($delay < config('max_delay')) {
'<option value="<%= $delay %>" <%== is_selected($delay) %>><%= $text %></option>',
% } elsif ($delay == config('max_delay')) {
'<option value="<%= $delay %>" <%== is_selected($delay) %>><%= $text %></option>',
% last;
% } else {
% my $text = ($delay == 1) ? l('24 hours') : l('%1 days', $delay);
'<option value="<%= config('max_delay') %>" <%== is_selected(config('max_delay')) %>><%= l('%1 days', config('max_delay')) %></option>',
% last;
% }
% }
% } else {
'<option value="<%= $delay %>" <%== is_selected($delay) %>><%= $text %></option>',
% }
% }
'</select>&nbsp;',
'<div class="checkbox">',
'<label>',
'<input id="first-view-', msg.real_short, '" type="checkbox" name="first-view"> <%= l('Delete at first view?') %>',
'</label>',
'</div>&nbsp;',
'<a href="#" class="btn btn-sm btn-default btn-primary modify-image" data-modlink="', link(msg.real_short, '', msg.token, true),'" data-modshort="', msg.real_short,'">',
'<%= l('Let\'s go!') %>',
'</a>',
'</div>',
'</form>',
'</div>',
'</div>'
].join('');
} else {
return [
'<div class="alert alert-danger">',
'<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>',
'<strong><%= l('Something bad happened') %></strong><br>',
cleanName(msg.filename, false),
'<br>',
cleanName(msg.msg, false),
'</div>'
].join('');
}
}
function bindddz(firstview, deleteday) {
$('#drag-and-drop-zone').dmUploader({
url: '<%== url_for('/') %>',
dataType: 'json',
allowedTypes: 'image/*',
maxFileSize: <%= config('max_file_size') %>,
onNewFile: function(id, file){
$('.messages').append([
'<div id="', id, '-div">',
cleanName(file.name), '<br>',
'<div class="progress">',
'<div id="', id, '"class="progress-bar progress-striped active width-zero" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">',
'<span id="', id, '-text" class="pull-left pdg-left-10"> 0%</span>',
'</div>',
'</div>',
'</div>'
].join(''));
},
onUploadProgress: function(id, percent){
var percentStr = ' '+percent+'%';
$('#'+id).prop('aria-valuenow', percent);
$('#'+id).css('width', percent+'%');
$('#'+id+'-text').html(percentStr);
},
onUploadSuccess: function(id, data){
data.msg.filename = cleanName(data.msg.filename);
$('#'+id+'-div').remove();
if ($('#copy-all').length === 0 && data.success) {
$('.messages').prepend([
'<div class="col-xs-12 col-sm-11 col-sm-offset-1">',
'<a id="copy-all" href="#" class="btn btn-info copy-all-to-clipboard-link">',
'<%= l('Copy all view links to clipboard') %>',
'</a>',
'</div>'
].join(''));
}
$('.messages').append(buildMessage(data.success, data.msg));
$('#del-'+data.msg.real_short).on('click', function(e) {
e.preventDefault();
rmFromShortHash(data.msg.short+'.'+data.msg.ext)
rmFromZipHash(data.msg.short);
rmFromRandomHash(data.msg.short);
});
$('#del-'+data.msg.real_short).on('click', delImage);
if (data.success) {
addToShortHash(data.msg.short+'.'+data.msg.ext);
addToZipHash(data.msg.short);
addToRandomHash(data.msg.short);
$('.close').unbind('click', evaluateCopyAll);
$('.close').on('click', evaluateCopyAll);
$('input[type=\'text\']').unbind("click", selectInput);
$('input[type=\'text\']').on("click", selectInput);
$('.copy-all-to-clipboard-link').unbind('click', copyAllToClipboard);
$('.copy-all-to-clipboard-link').on('click', copyAllToClipboard);
$('.modify-image').unbind('click', modifyImage);
$('.modify-image').on('click', modifyImage);
$('.copy-to-clipboard-link').unbind('click', clickOnCopyLink);
$('.copy-to-clipboard-link').on('click', clickOnCopyLink);
addItem(data.msg);
}
},
onUploadError: function(id, message){
$('.messages').append(buildMessage(false, ''));
},
onFileSizeError: function(file){
$('.messages').append(buildMessage(false, { filename: file.name, msg: '<%= l('The file exceed the size limit (%1)', config('max_file_size')) %>'}));
}
});
}
function upload_url(e) {
e.preventDefault();
var val = $('#lutim-file-url').val();
if (val !== undefined && val !== '') {
$('#lutim-file-url').prop('disabled', 'disabled');
$('.hidden-spin').css('display', 'block');
$.ajax({
url : '<%== url_for('/') %>',
type : 'POST',
data : {
'lutim-file-url' : val,
'format' : 'json',
'first-view' : ($('#first-view').prop('checked')) ? 1 : 0,
'crypt' : ($('#crypt').prop('checked')) ? 1 : 0,
'delete-day' : $('#delete-day').val()
},
success: function(data) {
data.msg.filename = cleanName(data.msg.filename);
$('.messages').append(buildMessage(data.success, data.msg));
if (data.success) {
if ($('#copy-all').length === 0) {
$('.messages').prepend([
'<div class="col-xs-12 col-sm-11 col-sm-offset-1">',
'<a id="copy-all" href="#" class="btn btn-info copy-all-to-clipboard-link">',
'<%= l('Copy all view links to clipboard') %>',
'</a>',
'</div>'
].join(''));
}
$('#lutim-file-url').val('');
addToShortHash(data.msg.short+'.'+data.msg.ext);
addToZipHash(data.msg.short);
addToRandomHash(data.msg.short);
$('#del-'+data.msg.real_short).on('click', delImage);
$('.close').unbind('click', evaluateCopyAll);
$('.close').on('click', evaluateCopyAll);
addItem(data.msg);
}
},
error: function() {
$('.messages').append(buildMessage(false, ''));
},
complete: function() {
$('#lutim-file-url').prop('disabled', '');
$('.hidden-spin').css('display', 'none');
$('.copy-all-to-clipboard-link').unbind('click', copyAllToClipboard);
$('.copy-all-to-clipboard-link').on('click', copyAllToClipboard);
$('.modify-image').unbind('click', modifyImage);
$('.modify-image').on('click', modifyImage);
$('.copy-to-clipboard-link').unbind('click', clickOnCopyLink);
$('.copy-to-clipboard-link').on('click', clickOnCopyLink);
}
});
}
}
function fileUpload(file) {
var fd = new FormData();
fd.append('file', file);
fd.append('format', 'json');
fd.append('first-view', ($('#first-view').prop('checked')) ? 1 : 0);
fd.append('crypt', ($('#crypt').prop('checked')) ? 1 : 0);
fd.append('delete-day', ($('#delete-day').val()));
$('.messages').append([
'<div id="1-div">', cleanName(file.name), '<br>',
'<div class="progress">',
'<div id="1" class="progress-bar progress-striped active width-zero" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">',
'<span id="1-text" class="pull-left pdg-left-10"> 0%</span>',
'</div>',
'</div>',
'</div>'
].join(''));
// Ajax Submit
$.ajax({
url: '<%== url_for('/') %>',
type: 'POST',
dataType: 'json',
data: fd,
cache: false,
contentType: false,
processData: false,
forceSync: false,
xhr: function(){
var xhrobj = $.ajaxSettings.xhr();
if(xhrobj.upload){
xhrobj.upload.addEventListener('progress', function(event) {
var percent = 0;
var position = event.loaded || event.position;
var total = event.total || e.totalSize;
if(event.lengthComputable){
percent = Math.ceil(position / total * 100);
}
var percentStr = ' '+percent+'%';
$('#1').prop('aria-valuenow', percent);
$('#1').css('width', percent+'%');
$('#1-text').html(percentStr);
}, false);
}
return xhrobj;
},
success: function (data, message, xhr){
$('#1-div').remove();
if ($('#copy-all').length === 0 && data.success) {
$('.messages').prepend([
'<div class="col-xs-12 col-sm-11 col-sm-offset-1">',
'<a id="copy-all" href="#" class="btn btn-info copy-all-to-clipboard-link">',
'<%= l('Copy all view links to clipboard') %>',
'</a>',
'</div>'
].join(''));
}
data.msg.filename = cleanName(data.msg.filename);
$('.messages').append(buildMessage(data.success, data.msg));
if (data.success) {
$('.close').unbind('click', evaluateCopyAll);
$('.close').on('click', evaluateCopyAll);
addItem(data.msg);
}
},
error: function (xhr, status, errMsg){
$('.messages').append(buildMessage(false, ''));
},
complete: function () {
$('.copy-all-to-clipboard-link').unbind('click', copyAllToClipboard);
$('.copy-all-to-clipboard-link').on('click', copyAllToClipboard);
$('.modify-image').unbind('click', modifyImage);
$('.modify-image').on('click', modifyImage);
$('.copy-to-clipboard-link').unbind('click', clickOnCopyLink);
$('.copy-to-clipboard-link').on('click', clickOnCopyLink);
}
});
}
function initPaste() {
/*
actually FF and Chrome doesn't handle paste events the same way...
for ff we need to create a editable div and register an event to it.
When user paste, the image is "really" pasted in the div. Then, we need to iterate throught
the div childs to get images. Previsouly FF didn't have the paste event so it was esay to figure on wich browser we were.
But firefox now have a paste event so I test it...
on Chrome the file object is directlyt in the clipboard.
*/
var b = 'FF';
try {
//FF
var cbe = new ClipboardEvent('hop');
} catch(hop) {
//under webkkit Clipboard doesn't have arguments...
b = 'WK'
}
if (b === 'FF') {
var pasteDiv = document.createElement('div');
pasteDiv.addEventListener('paste', onPasteFF);
pasteDiv.setAttribute('class', 'pasteZone');
pasteDiv.setAttribute('contenteditable', true);
document.getElementsByTagName('body')[0].appendChild(pasteDiv);
pasteDiv.focus();
document.addEventListener('click', function(event) {
var t = $(event.target);
switch (t[0].nodeName.toUpperCase()) {
case 'A':
case 'BUTTON':
case 'INPUT':
case 'SELECT':
case 'SPAN':
case 'LABEL':
break;
default:
if (t[0].parentNode.nodeName.toUpperCase() !== 'SELECT') {
pasteDiv.focus();
}
}
});
} else {
document.addEventListener('paste', onPaste);
}
}
function waitforpastedata(elem, savedcontent) {
if (elem.childNodes && elem.childNodes.length > 0) {
processpaste(elem, savedcontent);
} else {
var that = {
e: elem,
s: savedcontent
};
that.callself = function () {
waitforpastedata(that.e, that.s);
}
setTimeout(that.callself, 20);
}
}
function processpaste(elem, savedcontent) {
var pasteZone = document.getElementsByClassName('pasteZone')[0];
var f = new Image();
f.onload = function(){
var canvas = document.createElement('canvas');
canvas.width = f.width;
canvas.height = f.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(f, 0, 0, canvas.width, canvas.height);
canvas.toBlob(function(blob) {
var url = window.URL.createObjectURL(blob);
fileUpload(blob);
});
}
f.src = pasteZone.childNodes[0].src;
pasteZone.innerHTML = '';
}
function onPasteFF(e) {
var pasteZone = document.getElementsByClassName('pasteZone')[0];
waitforpastedata(pasteZone, 'savedcontent');
}
function onPaste(e) {
var items = e.clipboardData.items;
for(var i = 0; i < items.length; i++) {
var item = items[i];
if (/image/.test(item.type)) {
var file = item.getAsFile();
fileUpload(file);
} else {
//not image..
}
}
}