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)

2023년 11월 29일 수요일

python tornado 업로드 파일 사이즈.

용량이 큰 파일 업로드 시

net::ERR_CONNECTION_RESET 오류 발생할 경우.

http_server = tornado.httpserver.HTTPServer(app, max_buffer_size=10485760000)


upload_form.html

<!DOCTYPE html>
<html>
<head>
<title>File Upload Form</title>
</head>
<body>
<h2>File Upload Form</h2>
<form action="/" method="post" enctype="multipart/form-data">
<label for="file">Select a file:</label>
<input type="file" name="file" id="file"><br>
<input type="submit" value="Upload">
</form>
</body>
</html>

main.py

import os
import tornado.web
import tornado.ioloop

UPLOAD_DIR = "uploads" # Define the directory where uploaded files will be saved


class FileUploadHandler(tornado.web.RequestHandler):
def get(self):
self.render("upload_form.html") # Render the HTML form for file uploads

def post(self):
file_info = self.request.files['file'][0] # Get file information from the request

# Extract relevant file information
file_name = file_info['filename']
file_body = file_info['body']

# Save the uploaded file to the specified directory
file_path = os.path.join(UPLOAD_DIR, file_name)
with open(file_path, 'wb') as file:
file.write(file_body)

self.write(f"File '{file_name}' uploaded successfully.")


def make_app():
return tornado.web.Application([
(r"/", FileUploadHandler),
])


if __name__ == "__main__":
app = make_app()
print("Server is running on http://localhost:8888")
http_server = tornado.httpserver.HTTPServer(app, max_buffer_size=10485760000)
http_server.listen(8888)
tornado.ioloop.IOLoop.current().start()

2023년 11월 22일 수요일

Python을 Windows service로 실행하기

pywin32 설치

python -m pip install --upgrade pywin32 

- 가상환경에서 설치하면 안됨.


가상 환경 외부에서는 COM 객체, 서비스 등을 설치하고자 할 때

python Script/pywin32_postinstall.py -install


[myservice.py]

import win32serviceutil
import ctypes
import time

OutputDebugString = ctypes.windll.kernel32.OutputDebugStringW


class MyService(win32serviceutil.ServiceFramework):
_svc_name_ = 'MyService'
_svc_display_name_ = 'My Service'
is_running = False

def SvcStop(self):
OutputDebugString("MyService __SvcStop__")
self.is_running = False

def SvcDoRun(self):
self.is_running = True
while self.is_running:
OutputDebugString("MyService __loop__")
time.sleep(1)


if '__main__' == __name__:
win32serviceutil.HandleCommandLine(MyService)


관리자 권한으로 PowerSell 실행

python myservice.py install

python myservice.py start

python myservice.py stop

2022년 7월 26일 화요일

mssql insert image

 def insert(self, file_id, file_path):


    img = Image.open(file_path)

    w = int(img.width / 2)

    h = int(img.height / 2)

    img_resize = img.resize((w, h))

    img_resize.save('./temp.png')


    with open('./temp.png', 'rb') as fh:

        bindata = fh.read()

        buf = '0x' + binascii.hexlify(bindata).decode('ascii')

        query = f"INSERT INTO {self.tablename}(FILE_ID, FILE_DATA) VALUES ({file_id}, {buf})"

    self.cursor.execute(query)

    self.conn.commit()

2022년 5월 16일 월요일

docker mysql 설치

docker pull mysql

docker images

docker run --name mysql-container -e MYSQL_ROOT_PASSWORD=abcd -d -p 3306:3306 mysql:latest

docker ps

docker exec -it mysql-container bash


mysql -u root -p

mysql> create database tutorial;

mysql> create user [id]@'%' identified by 'abcd';

mysql> create user [id]@localhost identified by 'abcd';

mysql> grant all privileges on tutorial.* to [id]@'%';

mysql> grant all privileges on tutorial.* to [id]@localhost;

mysql> alter user thlee@'%' identified with mysql_native_password by 'abcd';

mysql> grant all privileges on tutorial.& to [id]@172.17.0.1 with grant option;


allowPublicKeyRetrival=true




select @@datadir;


docker volume

$ docker volume create my-vol

my-vol

$ docker volume ls

DRIVER    VOLUME NAME

local     my-vol

$ docker volume inspect my-vol

[

    {

        "CreatedAt": "2022-05-11T12:02:14Z",

        "Driver": "local",

        "Labels": {},

        "Mountpoint": "/var/lib/docker/volumes/my-vol/_data",

        "Name": "my-vol",

        "Options": {},

        "Scope": "local"

    }

]


2022년 5월 11일 수요일

javax.servlet.ServletException: java.lang.IllegalAccessError: class NiceID.Check.CPClient

C:\Program Files\NetBeans-13\netbeans\etc\netbeans.conf
에 설정된 jdkhome 경로와 프로젝트에서 설정한 java 버전이 다를 경우 발생

netbeans_jdkhome="C:\Program Files\ojdkbuild\java-17-openjdk-17.0.2.0.8-1"
경로를 프로젝트에서 설정한 java 와 동일한 경로로 설정.

2022년 5월 2일 월요일

java decompile

 

wget http://www.benf.org/other/cfr/cfr_0_115.jar
 
java -jar cfr_0_115.jar javaclasstodecompiles.class > javaclasstodecompiles.java 

2022년 4월 28일 목요일

Image to base64, base64 to image

PIL.UnidentifiedImageError: cannot identify image file


import base64

import io
from io import BytesIO
from PIL import Image

byteImgIO = io.BytesIO()
byteImg = Image.open('./images/img_small.png')
byteImg.save(byteImgIO, "PNG")
byteImgIO.seek(0)
byteImg = byteImgIO.read()
v2 = base64.b64encode(byteImg)
v3 = base64.b64decode(v2)
# i = Image.open(BytesIO(v3))
# i = i.convert('L')
i = BytesIO(v3)
i.seek(0)
i = Image.open(i)
i.save('./images/a.png')
print('finish')

Docker 에 postgres 설치

docker pull postgres

docker run -d -p 5432:5432 -e POSTGRES_PASSWORD="<mypwd>" --name PostgreSQL postgres

sudo docker exec --user="root" -it PostgreSQL "bash"

2022년 4월 26일 화요일

Python 으로 엑셀 셀 배경색 넣기.

color = 'ffffff'

bc = PatternFill(fgColor=Color(color, tint=0.5), bgColor=Color(color, tint=0.5), fill_type='gray125')

2022년 4월 25일 월요일

docker 로 kafka 설치, 실행

docker pull wurstmeister/kafka

docker pull wurstmeister/zookeeper


docker-compose.yml 생성

version: '2' services: zookeeper: image: wurstmeister/zookeeper ports: - "2181:2181" kafka: build: . ports: - "9092:9092" environment: KAFKA_ADVERTISED_HOST_NAME: 127.0.0.1 KAFKA_CREATE_TOPICS: "test:1:1" KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 volumes: - /var/run/docker.sock:/var/run/docker.sock


docker-compose.yml 파일이 있는 위치에서

docker-compose -f docker-compose.yml up -d


producer

max_request_size = 1048576

consumer

fetch_max_bytes = 52428800 max_partition_fetch_bytes: 1 * 1024 * 1024

이 파일은 파일 확인 절차를 통과하지 않았습니다.

빈 파일은 올라가지 않음.

vim /etc/php/7.4/apache2/php.ini

file_uploads = On

upload_max_filesize = 2048M


cd /var/www/html/mediawiki

sudo chown -R www-data:www-data images/

sudo chmod -R 755 images


vim LocalSettings.php

$wgFileBlacklist = [

  'exe', 'scr', 'dll', 'msi', 'vbs', 'bat', 'com', 'pif', 'cmd', 'vxd', 'cpl',

];

$wgFileExtensions = array( 'png', 'gif', 'jpg', 'jpeg', 'doc',

    'xls', 'mpp', 'pdf', 'ppt', 'tiff', 'bmp', 'docx', 'xlsx',

    'pptx', 'ps', 'odt', 'ods', 'odp', 'odg', 'zip', 'gz'

);


$wgStrictFileExtensions = false;

$wgTrustedMediaFormats[] = 'application/zip';

$wgAllowJavaUploads = true;


cd images

sudo vim .htaccess

<IfModule rewrite_module>

        RewriteEngine On

        RewriteOptions inherit

        RewriteCond %{QUERY_STRING} \.[^\\/:*?\x22<>|%]+(#|\?|$) [nocase]

        RewriteRule . - [forbidden]

        # Fix for bug T64289

        Options +FollowSymLinks

</IfModule>

docker redmine 설치

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