2024년 6월 10일 월요일

docker redmine 설치

docker-composer.yml

version: '3.1'

services:

     redmine:

          image: redmine

          restart: always

          container_name: redmine

          ports:

               - 3000:3000

          environment:

               REDMINE_DB_MYSQL: db

               REDMINE_DB_PASSWORD: redmine

               REDMINE_DB_DATABASE: redmine

               REDMINE_DB_ENCODING: utf8

#               REDMINE_NO_DB_MIGRATE: true

     db:

          image: mysql

          restart: always

          ports:

              - 3306:3306

          environment:

               MYSQL_ROOT_PASSWORD: redmine

               MYSQL_DATABASE: redmine

          command:

               - --character-set-server=utf8mb4

               - --collation-server=utf8mb4_unicode_ci

docker mantis 설치

참고: https://hub.docker.com/r/vimagick/mantisbt


- mantisbt 이미지 설치

docker pull vimagick/mantisbt:latest

- mysql 이미지 설치

docker pull mysql:5.7


- docker-compose.yml 파일 (빨간색 추가)

version: '3.8'

services:

mantisbt:

  image: vimagick/mantisbt:latest

  ports:

    - "8989:80"

  links:

    - mysql

  restart: always


mysql:

  image: mysql:5.7

  volumes:

    - ./data:/var/lib/mysql

  environment:

    - MYSQL_ROOT_PASSWORD=root

    - MYSQL_DATABASE=bugtracker

    - MYSQL_USER=mantisbt

    - MYSQL_PASSWORD=mantisbt

  restart: always


- 실행 (docker-compose.yml 파일 위치에서 실행)

$ docker-compose up -d


- 설정 (브라우저에서)

http://localhost:8989/admin/install.php

최초 로그인

administrator / root

Type of Database MySQL/MySQLi Hostname (for Database Server) mysql Username (for Database) mantisbt Password (for Database) mantisbt Database name (for Database) bugtracker Admin Username (to create Database if required) root Admin Password (to create Database if required) root

- email (/var/www/html/config_inc.php)

$g_phpMailer_method = PHPMAILER_METHOD_SMTP;
$g_administrator_email = 'admin@example.org';
$g_webmaster_email = 'webmaster@example.org';
$g_return_path_email = 'mantisbt@example.org';
$g_from_email = 'mantisbt@example.org';
$g_smtp_host = 'smtp.example.org';
$g_smtp_port = 25;
$g_smtp_connection_mode = 'tls';
$g_smtp_username = 'mantisbt';
$g_smtp_password = '********';

2024년 3월 15일 금요일

[python] subprocess

proc.py

import asyncio

from argparse import ArgumentParser

from asyncio import sleep



async def process_function(user, file_path):

    if user == 'user1':

        await sleep(2)

    result = f"Process for user {user}"

    with open(file_path, 'w') as fh:

        fh.write(result)

    print("Hello world")



if __name__ == '__main__':

    parser = ArgumentParser()

    parser.add_argument('--name')

    parser.add_argument('--path')


    args = parser.parse_args()

    user = args.name

    file_path = args.path


    asyncio.run(process_function(user, file_path)


=====================================================

main.py

import asyncio

import subprocess



async def proc(user):

    file_path = f"{user}_output.txt"

    process = subprocess.Popen(['python', 'proc.py', '--name', user, '--path', file_path])

    await asyncio.to_thread(process.wait)


    with open(f"{user}_output.txt", "r") as output_file:

        result = output_file.read()

        print(result)



async def broker():

    users = ['user1', 'user2', 'user3']

    await asyncio.gather(*(proc(user) for user in users))



def main():

    asyncio.run(broker())



if __name__ == "__main__":

    main()



2024년 3월 6일 수요일

[python] tornado 오래 걸리는 작업

 import json

import tornado.ioloop

import tornado.web

from src.exec import Executor



class ShellHandler(tornado.web.RequestHandler):

    async def long_running_task(self):

        """

        get, post 로 호출 시 오래 걸리는 작업.

        """

        executor = Executor()

        stdout, stderr = await executor.run()

        return stdout, stderr


    async def post(self):

        data = self.request.body.decode('utf-8')

        try:

            json_data = json.loads(data)

            self.write(f'received => {json_data}')

        except json.JSONDecodeError:

            self.write(f'error => {data}')


    async def get(self):

        ip_address = self.request.remote_ip

        stdout, stderr = await self.long_running_task()

        self.write(f"{ip_address}<br>stdout={stdout}<br>stdout={stderr}")



def make_app():

    return tornado.web.Application([

        (r"/shell", ShellHandler),

    ])



if __name__ == "__main__":

    app = make_app()

    app.listen(8888)

    print("Server is listening on port 8888")

    tornado.ioloop.IOLoop.current().start()


2024년 1월 26일 금요일

[python] pdf 를 이미지로 저장

  • poppler 다운로드 

https://github.com/oschwartz10612/poppler-windows/releases/tag/v23.11.0-0

  • 압축 해제

C:\poppler-23.11.0


  • pdf2image 설치

pip install pdf2image


def save_pdf_page_as_image(pdf_path, page_number, filename, output_dir):

    # PDF 파일에서 이미지로 변환
    name = os.path.splitext(filename)[0]
    output_path = os.path.join(output_dir, '{0}.png'.format(name))
    images = convert_from_path(pdf_path, first_page=page_number, last_page=page_number, poppler_path=r'C:\poppler-23.11.0\Library\bin')

    if images:
        # 첫 번째 이미지 선택 (페이지 번호에 해당하는 이미지)
        image = images[0]
        # 이미지 저장
        image.save(output_path, 'PNG')
    else:
        print(f'error.')

2023년 12월 13일 수요일

python pdf 에 워터마크 추가

출처] https://herohjk.com/41

import os

from PIL import Image
from reportlab.pdfgen.canvas import Canvas
from PyPDF2 import PdfReader, PdfWriter


class Watermark:
    def __init__(self, output_path, image_path, src_path, working_dir):
        self.output_path = output_path
        self.image_path = image_path
        self.src_path = src_path
        self.working_dir = working_dir
        if not os.path.exists(self.working_dir):
            os.makedirs(self.working_dir)

    @staticmethod
    def clear_white_background(image):
        """

        :param image:
        :return:
        """
        image = image.convert('RGBA')

        image_data = image.getdata()

        new_image_data = []

        for pixel in image_data:
            if pixel[0] > 240 and pixel[1] > 240 and pixel[2] > 240:
                new_image_data.append((0, 0, 0, 0))
            else:
                new_image_data.append(pixel)

        image.putdata(new_image_data)

        return image

    @staticmethod
    def image_to_pdf(image_path, pdf_path):
        """

        :param image_path:
        :param pdf_path:
        :return:
        """
        size = Image.open(image_path, 'r').size
        new_canvas = Canvas(pdf_path, pagesize=Image.open(image_path, 'r').size)
        new_canvas.drawImage(image=image_path, x=0, y=0, mask='auto')
        new_canvas.save()

    @staticmethod
    def pdf_merge(save_path, pdf_path, watermark_pdf_path):
        """

        :param save_path:
        :param pdf_path:
        :param watermark_pdf_path:
        :return:
        """
        pdf_file = open(pdf_path, 'rb')
        pdf_reader = PdfReader(pdf_file, strict=False)

        watermark_pdf_file = open(watermark_pdf_path, 'rb')
        watermark_pdf = PdfReader(watermark_pdf_file, strict=False).pages[0]

        pdf_writer = PdfWriter()

        for pageNum in range(len(pdf_reader.pages)):

            page_obj = pdf_reader.pages[pageNum]

            x = (page_obj.mediabox[2] - watermark_pdf.mediabox[2]) / 2
            y = (page_obj.mediabox[3] - watermark_pdf.mediabox[3]) / 2
            watermark_pdf.add_transformation(Transformation().translate(tx=x, ty=y))
            page_obj.merge_page(page2=watermark_pdf, expand=False)
            pdf_writer.add_page(page_obj)

        result_file = open(save_path, 'wb')
        pdf_writer.write(result_file)

    def convert(self):
        """

        :return:
        """
        image = Image.open(self.image_path, 'r')
        clear_image = self.clear_white_background(image)
        clear_image_path = os.path.join(self.working_dir, 'clear_image.png')
        clear_image.save(clear_image_path)
        watermark_pdf_path = os.path.join(self.working_dir, 'watermark_pdf.pdf')
        self.image_to_pdf(clear_image_path, watermark_pdf_path)
        self.pdf_merge(self.output_path, self.src_path, watermark_pdf_path)

docker redmine 설치

docker-composer.yml version: '3.1' services:      redmine:           image: redmine           restart: always           container_na...