{"id":38611255,"url":"https://github.com/c2corg/v6_images","last_synced_at":"2026-01-17T08:44:54.591Z","repository":{"id":8805452,"uuid":"59824689","full_name":"c2corg/v6_images","owner":"c2corg","description":"Images handling app for c2c.org v6","archived":false,"fork":false,"pushed_at":"2025-06-10T11:42:53.000Z","size":903,"stargazers_count":1,"open_issues_count":40,"forks_count":2,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-06-10T12:38:49.976Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/c2corg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":"https://www.helloasso.com/associations/camptocamp-association/adhesions/adhesion-camptocamp-association"}},"created_at":"2016-05-27T09:57:38.000Z","updated_at":"2024-09-16T13:40:13.000Z","dependencies_parsed_at":"2023-02-19T05:31:28.950Z","dependency_job_id":"f6f190fd-1488-4dac-9dde-5717bc14793d","html_url":"https://github.com/c2corg/v6_images","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/c2corg/v6_images","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c2corg%2Fv6_images","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c2corg%2Fv6_images/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c2corg%2Fv6_images/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c2corg%2Fv6_images/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/c2corg","download_url":"https://codeload.github.com/c2corg/v6_images/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c2corg%2Fv6_images/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28504460,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T06:57:29.758Z","status":"ssl_error","status_checked_at":"2026-01-17T06:56:03.931Z","response_time":85,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-17T08:44:50.165Z","updated_at":"2026-01-17T08:44:54.578Z","avatar_url":"https://github.com/c2corg.png","language":"Python","funding_links":["https://www.helloasso.com/associations/camptocamp-association/adhesions/adhesion-camptocamp-association"],"categories":[],"sub_categories":[],"readme":"# Image backend service\n\n[![GitHub license](https://img.shields.io/github/license/c2corg/v6_images.svg)](https://github.com/c2corg/v6_images/blob/master/LICENSE)\n![Build status](https://github.com/c2corg/v6_images/actions/workflows/build.yml/badge.svg)\n![Github Code scanning](https://github.com/c2corg/v6_images/workflows/Github%20Code%20scanning/badge.svg?branch=master)\n[![Total alerts](https://img.shields.io/lgtm/alerts/g/c2corg/v6_images.svg?logo=lgtm\u0026logoWidth=18)](https://lgtm.com/projects/g/c2corg/v6_images/alerts/)\n[![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/c2corg/v6_images.svg?logo=lgtm\u0026logoWidth=18)](https://lgtm.com/projects/g/c2corg/v6_images/context:python)\n[![Known Vulnerabilities](https://snyk.io/test/github/c2corg/v6_images/badge.svg)](https://snyk.io/test/github/c2corg/v6_images)\n\nThis project handles receiving images from the user and generating smaller\nversions. It is using docker to be able to run it either together with the\nAPI machine or on a separate machine.\n\n## Upload\n\nThe original image uploaded by the user is:\n\n- optionally rotate the image according to the EXIF orientation value\n- uniquely renamed using a timestamp and random number;\n- stored locally in an \"incoming\" directory;\n- converted to smaller sizes.\n\nThe image is uploaded immediately to S3.\nThe user receives the renamed filename.\n\n## Activation\n\nThe user associates the filename to a document, which is stored in the API.\nAt that time, a request is sent to image backend to move original and resized\nimages from the incoming bucket to the public bucket. This step ensures the\nimage is associated with an authenticated user.\n\n## Configuration\n\nConfiguration should be set by environment variables:\n\n``STORAGE_BACKEND``: (required) ``s3`` or ``local``\n\n- ``s3``: requires ``INCOMING_BUCKET`` and ``ACTIVE_BUCKET``, should be used in\n  production.\n- ``local``: requires ``INCOMING_FOLDER`` and ``ACTIVE_FOLDER``, should be used\n  for tests and development.\n\n``TEMP_FOLDER``: (required) Local folder to store images temporarily.\n\n``INCOMING_FOLDER``: Local folder for incoming files.\n\n``ACTIVE_FOLDER``: Local folder for active files.\n\n``INCOMING_BUCKET``: Name bucket for incoming files.\n\n``INCOMING_PREFIX``: Prefix of the incoming bucket connection options.\n\n``ACTIVE_BUCKET``: Name bucket for active files.\n\n``ACTIVE_PREFIX``: Prefix of the active bucket connection options.\n\n*PREFIX_*``ENDPOINT``: Endpoint url for corresponding prefix.\n\n*PREFIX_*``ACCESS_KEY_ID``: API key for corresponding prefix.\n\n*PREFIX_*``SECRET_KEY``: Secret key for corresponding prefix.\n\n*PREFIX_*``DEFAULT_REGION``: Default region for corresponding prefix.\n\n``S3_SIGNATURE_VERSION``: S3 signature version ('s3' or 's3v4'), see [docs](https://botocore.readthedocs.io/en/stable/reference/config.html#botocore.config.Config).\n\n``API_SECRET_KEY``: API secret key, needed to publish images on the active\nbucket.\n\n``V5_DATABASE_URL``: Address of the V5 database for the migration script.\n\n``ROUTE_PREFIX``: Path prefix for serving the photo backend API.\n\n``RESIZING_CONFIG``: Configuration of the thumbnail names and sizes serialized in JSON. See c2corg\\_images/__init__.py for a description of the format.\n\n``AUTO_ORIENT_ORIGINAL``: `1` to rotate the uploaded image according to the EXIF orientation. Default is `0`.\n\n``CACHE_CONTROL``: Cache-Control value to be set to all the images uploaded to s3. Default is `public, max-age=3600`.\n\nHere is an example configuration with S3 backend on exoscale:\n\n```bash\nSTORAGE_BACKEND: s3\n\nTEMP_FOLDER: /srv/images/temp\nINCOMING_FOLDER:\nACTIVE_FOLDER:\n\nINCOMING_BUCKET: c2corg_demov6_incoming\nINCOMING_PREFIX: EXO\nACTIVE_BUCKET: c2corg_demov6_active\nACTIVE_PREFIX: EXO\nEXO_ENDPOINT: https://sos.exo.io\nEXO_ACCESS_KEY_ID: xxx\nEXO_SECRET_KEY: xxx\n\nAPI_SECRET_KEY: xxx\n\nV5_DATABASE_URL: postgresql://www-data:www-data@postgres/c2corg\n```\n\n## Cleaning\n\nThe files which were not activated are automatically expired by S3.\n\n## Building and running with Docker\n\n`make run`\n\n## Launch images migration from V5 to V6\n\nThe migration retrieves a list of images from the v5 database. The connection\nto the database can be defined as environment variable, for example:\n\n```bash\nV5_DATABASE_URL: postgresql://www-data:www-data@postgres/c2corg\n```\n\nThe migration script iterates through v5 images. For each *original* image\nfound:\n\n- If the image already exists in publication bucket, nothing is done (only\n  migrate the new ones).\n- If the image does not exists in the v6 bucket:\n  - the *original* image is copied locally,\n  - *resized* images are produced according to configuration,\n  - *original* and *resized* images are pushed on publication bucket.\n\nTo run the migration script:\n\n``docker-compose exec images migrate``\n\n``docker-compose exec images migrate --help`` to get options list.\n\n## Generate *resized* images after migration\n\nThis can be used to change the size or quality of *resized* images.\n\nThis script iterates through *published* images. For each *original* image\nfound:\n\n- the *original* image is copied locally,\n- *resized* images are produced according to configuration,\n- *resized* images are pushed in publication bucket, overwriting old ones.\n\nTo regenerate the *resized* images:\n\n``docker-compose exec images resize``\n\n``docker-compose exec images resize --help`` to get options list.\n\n## Release on docker hub\n\nThe project is built by Github actions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc2corg%2Fv6_images","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fc2corg%2Fv6_images","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc2corg%2Fv6_images/lists"}