Compare commits
25 Commits
exdb
...
338643b0d7
| Author | SHA1 | Date | |
|---|---|---|---|
| 338643b0d7 | |||
| e992e834da | |||
| c6969d7afa | |||
| 82d0e55945 | |||
| b872f377b2 | |||
| a6b816c9f2 | |||
| 2913a435c1 | |||
| 051916f9f6 | |||
| b8d7029965 | |||
| 6f0d8d15fd | |||
| 80ccaace3d | |||
| 95b787c819 | |||
| 3d195973fc | |||
| d851e7e4ad | |||
| 9d0d3ea102 | |||
| 37a253e63a | |||
| bc74b14cbc | |||
| 49b3ee7342 | |||
| 26e8e68dbd | |||
| 44ad30093c | |||
| bcfcceb068 | |||
| 9215ba8f9f | |||
| c0fb177d02 | |||
| 09e39987e2 | |||
| 6f79d9a4be |
4
.gitignore
vendored
4
.gitignore
vendored
@ -157,6 +157,10 @@ dmypy.json
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# migration files
|
||||
rog/migrations/
|
||||
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintainted in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
|
||||
@ -51,7 +51,10 @@ RUN pip install gunicorn
|
||||
|
||||
#RUN ["chmod", "+x", "wait-for.sh"]
|
||||
|
||||
RUN pip install -r requirements.txt
|
||||
# xlsxwriterを追加
|
||||
RUN pip install -r requirements.txt \
|
||||
&& pip install django-cors-headers \
|
||||
&& pip install xlsxwriter gunicorn
|
||||
|
||||
COPY . /app
|
||||
|
||||
|
||||
35
Dockerfile.supervisor
Normal file
35
Dockerfile.supervisor
Normal file
@ -0,0 +1,35 @@
|
||||
FROM nginx:alpine
|
||||
|
||||
# Create necessary directories and set permissions
|
||||
RUN mkdir -p /usr/share/nginx/html \
|
||||
&& mkdir -p /var/log/nginx \
|
||||
&& mkdir -p /var/cache/nginx \
|
||||
&& chown -R nginx:nginx /usr/share/nginx/html \
|
||||
&& chown -R nginx:nginx /var/log/nginx \
|
||||
&& chown -R nginx:nginx /var/cache/nginx \
|
||||
&& chmod -R 755 /usr/share/nginx/html
|
||||
|
||||
# Copy files - notice the change in the source path
|
||||
COPY supervisor/html/* /usr/share/nginx/html/
|
||||
COPY supervisor/nginx/default.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# メディアディレクトリを作成
|
||||
RUN mkdir -p /app/media && chmod 755 /app/media
|
||||
|
||||
# 静的ファイルをコピー
|
||||
#COPY ./static /usr/share/nginx/html/static
|
||||
|
||||
# 権限の設定
|
||||
RUN chown -R nginx:nginx /app/media
|
||||
|
||||
# Set final permissions
|
||||
RUN chown -R nginx:nginx /usr/share/nginx/html \
|
||||
&& chmod -R 755 /usr/share/nginx/html \
|
||||
&& touch /var/log/nginx/access.log \
|
||||
&& touch /var/log/nginx/error.log \
|
||||
&& chown -R nginx:nginx /var/log/nginx \
|
||||
&& chown -R nginx:nginx /etc/nginx/conf.d
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
19
SumasenLibs/excel_lib/README.md
Normal file
19
SumasenLibs/excel_lib/README.md
Normal file
@ -0,0 +1,19 @@
|
||||
# SumasenExcel Library
|
||||
|
||||
Excel操作のためのシンプルなPythonライブラリです。
|
||||
|
||||
## インストール方法
|
||||
|
||||
```bash
|
||||
pip install -e .
|
||||
|
||||
## 使用方法
|
||||
from sumaexcel import SumasenExcel
|
||||
|
||||
excel = SumasenExcel("path/to/file.xlsx")
|
||||
data = excel.read_excel()
|
||||
|
||||
## ライセンス
|
||||
|
||||
MIT License
|
||||
|
||||
14
SumasenLibs/excel_lib/docker/docker-compose.yml
Normal file
14
SumasenLibs/excel_lib/docker/docker-compose.yml
Normal file
@ -0,0 +1,14 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
python:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: docker/python/Dockerfile
|
||||
volumes:
|
||||
- ..:/app
|
||||
environment:
|
||||
- PYTHONPATH=/app
|
||||
command: /bin/bash
|
||||
tty: true
|
||||
|
||||
27
SumasenLibs/excel_lib/docker/python/Dockerfile
Normal file
27
SumasenLibs/excel_lib/docker/python/Dockerfile
Normal file
@ -0,0 +1,27 @@
|
||||
FROM python:3.9-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 必要なシステムパッケージのインストール
|
||||
RUN apt-get update && apt-get install -y \
|
||||
git \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Pythonパッケージのインストール
|
||||
COPY requirements.txt .
|
||||
COPY setup.py .
|
||||
COPY README.md .
|
||||
COPY . .
|
||||
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# 開発用パッケージのインストール
|
||||
RUN pip install --no-cache-dir \
|
||||
pytest \
|
||||
pytest-cov \
|
||||
flake8
|
||||
|
||||
|
||||
# パッケージのインストール
|
||||
RUN pip install -e .
|
||||
|
||||
5
SumasenLibs/excel_lib/requirements.txt
Normal file
5
SumasenLibs/excel_lib/requirements.txt
Normal file
@ -0,0 +1,5 @@
|
||||
openpyxl>=3.0.0
|
||||
pandas>=1.0.0
|
||||
pillow>=8.0.0
|
||||
configparser>=5.0.0
|
||||
|
||||
25
SumasenLibs/excel_lib/setup.py
Normal file
25
SumasenLibs/excel_lib/setup.py
Normal file
@ -0,0 +1,25 @@
|
||||
# setup.py
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="sumaexcel",
|
||||
version="0.1.0",
|
||||
packages=find_packages(),
|
||||
install_requires=[
|
||||
"openpyxl>=3.0.0",
|
||||
"pandas>=1.0.0"
|
||||
],
|
||||
author="Akira Miyata",
|
||||
author_email="akira.miyata@sumasen.net",
|
||||
description="Excel handling library",
|
||||
long_description=open("README.md").read(),
|
||||
long_description_content_type="text/markdown",
|
||||
url="https://github.com/akiramiyata/sumaexcel",
|
||||
classifiers=[
|
||||
"Programming Language :: Python :: 3",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Operating System :: OS Independent",
|
||||
],
|
||||
python_requires=">=3.6",
|
||||
)
|
||||
|
||||
4
SumasenLibs/excel_lib/sumaexcel/__init__.py
Normal file
4
SumasenLibs/excel_lib/sumaexcel/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
from .sumaexcel import SumasenExcel
|
||||
|
||||
__version__ = "0.1.0"
|
||||
__all__ = ["SumasenExcel"]
|
||||
102
SumasenLibs/excel_lib/sumaexcel/conditional.py
Normal file
102
SumasenLibs/excel_lib/sumaexcel/conditional.py
Normal file
@ -0,0 +1,102 @@
|
||||
# sumaexcel/conditional.py
|
||||
from typing import Dict, Any, List, Union
|
||||
from openpyxl.formatting.rule import Rule, ColorScaleRule, DataBarRule, IconSetRule
|
||||
from openpyxl.styles import PatternFill, Font, Border, Side
|
||||
from openpyxl.worksheet.worksheet import Worksheet
|
||||
|
||||
class ConditionalFormatManager:
|
||||
"""Handle conditional formatting in Excel"""
|
||||
|
||||
def __init__(self, worksheet: Worksheet):
|
||||
self.worksheet = worksheet
|
||||
|
||||
def add_color_scale(
|
||||
self,
|
||||
cell_range: str,
|
||||
min_color: str = "00FF0000", # Red
|
||||
mid_color: str = "00FFFF00", # Yellow
|
||||
max_color: str = "0000FF00" # Green
|
||||
) -> None:
|
||||
"""Add color scale conditional formatting"""
|
||||
rule = ColorScaleRule(
|
||||
start_type='min',
|
||||
start_color=min_color,
|
||||
mid_type='percentile',
|
||||
mid_value=50,
|
||||
mid_color=mid_color,
|
||||
end_type='max',
|
||||
end_color=max_color
|
||||
)
|
||||
self.worksheet.conditional_formatting.add(cell_range, rule)
|
||||
|
||||
def add_data_bar(
|
||||
self,
|
||||
cell_range: str,
|
||||
color: str = "000000FF", # Blue
|
||||
show_value: bool = True
|
||||
) -> None:
|
||||
"""Add data bar conditional formatting"""
|
||||
rule = DataBarRule(
|
||||
start_type='min',
|
||||
end_type='max',
|
||||
color=color,
|
||||
showValue=show_value
|
||||
)
|
||||
self.worksheet.conditional_formatting.add(cell_range, rule)
|
||||
|
||||
def add_icon_set(
|
||||
self,
|
||||
cell_range: str,
|
||||
icon_style: str = '3Arrows', # '3Arrows', '3TrafficLights', '3Signs'
|
||||
reverse_icons: bool = False
|
||||
) -> None:
|
||||
"""Add icon set conditional formatting"""
|
||||
rule = IconSetRule(
|
||||
icon_style=icon_style,
|
||||
type='percent',
|
||||
values=[0, 33, 67],
|
||||
reverse_icons=reverse_icons
|
||||
)
|
||||
self.worksheet.conditional_formatting.add(cell_range, rule)
|
||||
|
||||
def add_custom_rule(
|
||||
self,
|
||||
cell_range: str,
|
||||
rule_type: str,
|
||||
formula: str,
|
||||
fill_color: str = None,
|
||||
font_color: str = None,
|
||||
bold: bool = None,
|
||||
border_style: str = None,
|
||||
border_color: str = None
|
||||
) -> None:
|
||||
"""Add custom conditional formatting rule"""
|
||||
dxf = {}
|
||||
if fill_color:
|
||||
dxf['fill'] = PatternFill(start_color=fill_color, end_color=fill_color)
|
||||
if font_color or bold is not None:
|
||||
dxf['font'] = Font(color=font_color, bold=bold)
|
||||
if border_style and border_color:
|
||||
side = Side(style=border_style, color=border_color)
|
||||
dxf['border'] = Border(left=side, right=side, top=side, bottom=side)
|
||||
|
||||
rule = Rule(type=rule_type, formula=[formula], dxf=dxf)
|
||||
self.worksheet.conditional_formatting.add(cell_range, rule)
|
||||
|
||||
def copy_conditional_format(
|
||||
self,
|
||||
source_range: str,
|
||||
target_range: str
|
||||
) -> None:
|
||||
"""Copy conditional formatting from one range to another"""
|
||||
source_rules = self.worksheet.conditional_formatting.get(source_range)
|
||||
if source_rules:
|
||||
for rule in source_rules:
|
||||
self.worksheet.conditional_formatting.add(target_range, rule)
|
||||
|
||||
def clear_conditional_format(
|
||||
self,
|
||||
cell_range: str
|
||||
) -> None:
|
||||
"""Clear conditional formatting from specified range"""
|
||||
self.worksheet.conditional_formatting.delete(cell_range)
|
||||
77
SumasenLibs/excel_lib/sumaexcel/image.py
Normal file
77
SumasenLibs/excel_lib/sumaexcel/image.py
Normal file
@ -0,0 +1,77 @@
|
||||
# sumaexcel/image.py
|
||||
from typing import Optional, Tuple, Union
|
||||
from pathlib import Path
|
||||
import os
|
||||
from PIL import Image
|
||||
from openpyxl.drawing.image import Image as XLImage
|
||||
from openpyxl.worksheet.worksheet import Worksheet
|
||||
|
||||
class ImageManager:
|
||||
"""Handle image operations in Excel"""
|
||||
|
||||
def __init__(self, worksheet: Worksheet):
|
||||
self.worksheet = worksheet
|
||||
self.temp_dir = Path("/tmp/sumaexcel_images")
|
||||
self.temp_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def add_image(
|
||||
self,
|
||||
image_path: Union[str, Path],
|
||||
cell_coordinates: Tuple[int, int],
|
||||
size: Optional[Tuple[int, int]] = None,
|
||||
keep_aspect_ratio: bool = True,
|
||||
anchor_type: str = 'absolute'
|
||||
) -> None:
|
||||
"""Add image to worksheet at specified position"""
|
||||
# Convert path to Path object
|
||||
image_path = Path(image_path)
|
||||
|
||||
# Open and process image
|
||||
with Image.open(image_path) as img:
|
||||
# Get original size
|
||||
orig_width, orig_height = img.size
|
||||
|
||||
# Calculate new size if specified
|
||||
if size:
|
||||
target_width, target_height = size
|
||||
if keep_aspect_ratio:
|
||||
ratio = min(target_width/orig_width, target_height/orig_height)
|
||||
target_width = int(orig_width * ratio)
|
||||
target_height = int(orig_height * ratio)
|
||||
|
||||
# Resize image
|
||||
img = img.resize((target_width, target_height), Image.LANCZOS)
|
||||
|
||||
# Save temporary resized image
|
||||
temp_path = self.temp_dir / f"temp_{image_path.name}"
|
||||
img.save(temp_path)
|
||||
image_path = temp_path
|
||||
|
||||
# Create Excel image object
|
||||
excel_image = XLImage(str(image_path))
|
||||
|
||||
# Add to worksheet
|
||||
self.worksheet.add_image(excel_image, anchor=f'{cell_coordinates[0]}{cell_coordinates[1]}')
|
||||
|
||||
def add_image_absolute(
|
||||
self,
|
||||
image_path: Union[str, Path],
|
||||
position: Tuple[int, int],
|
||||
size: Optional[Tuple[int, int]] = None
|
||||
) -> None:
|
||||
"""Add image with absolute positioning"""
|
||||
excel_image = XLImage(str(image_path))
|
||||
if size:
|
||||
excel_image.width, excel_image.height = size
|
||||
excel_image.anchor = 'absolute'
|
||||
excel_image.top, excel_image.left = position
|
||||
self.worksheet.add_image(excel_image)
|
||||
|
||||
def cleanup(self) -> None:
|
||||
"""Clean up temporary files"""
|
||||
for file in self.temp_dir.glob("temp_*"):
|
||||
file.unlink()
|
||||
|
||||
def __del__(self):
|
||||
"""Cleanup on object destruction"""
|
||||
self.cleanup()
|
||||
96
SumasenLibs/excel_lib/sumaexcel/merge.py
Normal file
96
SumasenLibs/excel_lib/sumaexcel/merge.py
Normal file
@ -0,0 +1,96 @@
|
||||
# sumaexcel/merge.py
|
||||
from typing import List, Tuple, Dict
|
||||
from openpyxl.worksheet.worksheet import Worksheet
|
||||
from openpyxl.worksheet.merge import MergedCellRange
|
||||
|
||||
class MergeManager:
|
||||
"""Handle merge cell operations"""
|
||||
|
||||
def __init__(self, worksheet: Worksheet):
|
||||
self.worksheet = worksheet
|
||||
self._merged_ranges: List[MergedCellRange] = []
|
||||
self._load_merged_ranges()
|
||||
|
||||
def _load_merged_ranges(self) -> None:
|
||||
"""Load existing merged ranges from worksheet"""
|
||||
self._merged_ranges = list(self.worksheet.merged_cells.ranges)
|
||||
|
||||
def merge_cells(
|
||||
self,
|
||||
start_row: int,
|
||||
start_col: int,
|
||||
end_row: int,
|
||||
end_col: int
|
||||
) -> None:
|
||||
"""Merge cells in specified range"""
|
||||
self.worksheet.merge_cells(
|
||||
start_row=start_row,
|
||||
start_column=start_col,
|
||||
end_row=end_row,
|
||||
end_column=end_col
|
||||
)
|
||||
self._load_merged_ranges()
|
||||
|
||||
def unmerge_cells(
|
||||
self,
|
||||
start_row: int,
|
||||
start_col: int,
|
||||
end_row: int,
|
||||
end_col: int
|
||||
) -> None:
|
||||
"""Unmerge cells in specified range"""
|
||||
self.worksheet.unmerge_cells(
|
||||
start_row=start_row,
|
||||
start_column=start_col,
|
||||
end_row=end_row,
|
||||
end_column=end_col
|
||||
)
|
||||
self._load_merged_ranges()
|
||||
|
||||
def copy_merged_cells(
|
||||
self,
|
||||
source_range: Tuple[int, int, int, int],
|
||||
target_start_row: int,
|
||||
target_start_col: int
|
||||
) -> None:
|
||||
"""Copy merged cells from source range to target position"""
|
||||
src_row1, src_col1, src_row2, src_col2 = source_range
|
||||
row_offset = target_start_row - src_row1
|
||||
col_offset = target_start_col - src_col1
|
||||
|
||||
for merged_range in self._merged_ranges:
|
||||
if (src_row1 <= merged_range.min_row <= src_row2 and
|
||||
src_col1 <= merged_range.min_col <= src_col2):
|
||||
new_row1 = merged_range.min_row + row_offset
|
||||
new_col1 = merged_range.min_col + col_offset
|
||||
new_row2 = merged_range.max_row + row_offset
|
||||
new_col2 = merged_range.max_col + col_offset
|
||||
|
||||
self.merge_cells(new_row1, new_col1, new_row2, new_col2)
|
||||
|
||||
def shift_merged_cells(
|
||||
self,
|
||||
start_row: int,
|
||||
rows: int = 0,
|
||||
cols: int = 0
|
||||
) -> None:
|
||||
"""Shift merged cells by specified number of rows and columns"""
|
||||
new_ranges = []
|
||||
for merged_range in self._merged_ranges:
|
||||
if merged_range.min_row >= start_row:
|
||||
new_row1 = merged_range.min_row + rows
|
||||
new_col1 = merged_range.min_col + cols
|
||||
new_row2 = merged_range.max_row + rows
|
||||
new_col2 = merged_range.max_col + cols
|
||||
|
||||
self.worksheet.unmerge_cells(
|
||||
start_row=merged_range.min_row,
|
||||
start_column=merged_range.min_col,
|
||||
end_row=merged_range.max_row,
|
||||
end_column=merged_range.max_col
|
||||
)
|
||||
|
||||
new_ranges.append((new_row1, new_col1, new_row2, new_col2))
|
||||
|
||||
for new_range in new_ranges:
|
||||
self.merge_cells(*new_range)
|
||||
148
SumasenLibs/excel_lib/sumaexcel/page.py
Normal file
148
SumasenLibs/excel_lib/sumaexcel/page.py
Normal file
@ -0,0 +1,148 @@
|
||||
# sumaexcel/page.py
|
||||
from typing import Optional, Dict, Any, Union
|
||||
from openpyxl.worksheet.worksheet import Worksheet
|
||||
from openpyxl.worksheet.page import PageMargins, PrintPageSetup
|
||||
|
||||
# sumaexcel/page.py (continued)
|
||||
|
||||
class PageManager:
|
||||
"""Handle page setup and header/footer settings"""
|
||||
|
||||
def __init__(self, worksheet: Worksheet):
|
||||
self.worksheet = worksheet
|
||||
|
||||
def set_page_setup(
|
||||
self,
|
||||
orientation: str = 'portrait',
|
||||
paper_size: int = 9, # A4
|
||||
fit_to_height: Optional[int] = None,
|
||||
fit_to_width: Optional[int] = None,
|
||||
scale: Optional[int] = None
|
||||
) -> None:
|
||||
"""Configure page setup
|
||||
|
||||
Args:
|
||||
orientation: 'portrait' or 'landscape'
|
||||
paper_size: paper size (e.g., 9 for A4)
|
||||
fit_to_height: number of pages tall
|
||||
fit_to_width: number of pages wide
|
||||
scale: zoom scale (1-400)
|
||||
"""
|
||||
setup = PrintPageSetup(
|
||||
orientation=orientation,
|
||||
paperSize=paper_size,
|
||||
scale=scale,
|
||||
fitToHeight=fit_to_height,
|
||||
fitToWidth=fit_to_width
|
||||
)
|
||||
self.worksheet.page_setup = setup
|
||||
|
||||
def set_margins(
|
||||
self,
|
||||
left: float = 0.7,
|
||||
right: float = 0.7,
|
||||
top: float = 0.75,
|
||||
bottom: float = 0.75,
|
||||
header: float = 0.3,
|
||||
footer: float = 0.3
|
||||
) -> None:
|
||||
"""Set page margins in inches"""
|
||||
margins = PageMargins(
|
||||
left=left,
|
||||
right=right,
|
||||
top=top,
|
||||
bottom=bottom,
|
||||
header=header,
|
||||
footer=footer
|
||||
)
|
||||
self.worksheet.page_margins = margins
|
||||
|
||||
def set_header_footer(
|
||||
self,
|
||||
odd_header: Optional[str] = None,
|
||||
odd_footer: Optional[str] = None,
|
||||
even_header: Optional[str] = None,
|
||||
even_footer: Optional[str] = None,
|
||||
first_header: Optional[str] = None,
|
||||
first_footer: Optional[str] = None,
|
||||
different_first: bool = False,
|
||||
different_odd_even: bool = False
|
||||
) -> None:
|
||||
"""Set headers and footers
|
||||
|
||||
Format codes:
|
||||
- &P: Page number
|
||||
- &N: Total pages
|
||||
- &D: Date
|
||||
- &T: Time
|
||||
- &[Tab]: Sheet name
|
||||
- &[Path]: File path
|
||||
- &[File]: File name
|
||||
- &[Tab]: Worksheet name
|
||||
"""
|
||||
self.worksheet.oddHeader.left = odd_header or ""
|
||||
self.worksheet.oddFooter.left = odd_footer or ""
|
||||
|
||||
if different_odd_even:
|
||||
self.worksheet.evenHeader.left = even_header or ""
|
||||
self.worksheet.evenFooter.left = even_footer or ""
|
||||
|
||||
if different_first:
|
||||
self.worksheet.firstHeader.left = first_header or ""
|
||||
self.worksheet.firstFooter.left = first_footer or ""
|
||||
|
||||
self.worksheet.differentFirst = different_first
|
||||
self.worksheet.differentOddEven = different_odd_even
|
||||
|
||||
def set_print_area(self, range_string: str) -> None:
|
||||
"""Set print area
|
||||
|
||||
Args:
|
||||
range_string: Cell range in A1 notation (e.g., 'A1:H42')
|
||||
"""
|
||||
self.worksheet.print_area = range_string
|
||||
|
||||
def set_print_title_rows(self, rows: str) -> None:
|
||||
"""Set rows to repeat at top of each page
|
||||
|
||||
Args:
|
||||
rows: Row range (e.g., '1:3')
|
||||
"""
|
||||
self.worksheet.print_title_rows = rows
|
||||
|
||||
def set_print_title_columns(self, cols: str) -> None:
|
||||
"""Set columns to repeat at left of each page
|
||||
|
||||
Args:
|
||||
cols: Column range (e.g., 'A:B')
|
||||
"""
|
||||
self.worksheet.print_title_cols = cols
|
||||
|
||||
def set_print_options(
|
||||
self,
|
||||
grid_lines: bool = False,
|
||||
horizontal_centered: bool = False,
|
||||
vertical_centered: bool = False,
|
||||
headers: bool = False
|
||||
) -> None:
|
||||
"""Set print options"""
|
||||
self.worksheet.print_gridlines = grid_lines
|
||||
self.worksheet.print_options.horizontalCentered = horizontal_centered
|
||||
self.worksheet.print_options.verticalCentered = vertical_centered
|
||||
self.worksheet.print_options.headers = headers
|
||||
|
||||
class PaperSizes:
|
||||
"""Standard paper size constants"""
|
||||
LETTER = 1
|
||||
LETTER_SMALL = 2
|
||||
TABLOID = 3
|
||||
LEDGER = 4
|
||||
LEGAL = 5
|
||||
STATEMENT = 6
|
||||
EXECUTIVE = 7
|
||||
A3 = 8
|
||||
A4 = 9
|
||||
A4_SMALL = 10
|
||||
A5 = 11
|
||||
B4 = 12
|
||||
B5 = 13
|
||||
115
SumasenLibs/excel_lib/sumaexcel/styles.py
Normal file
115
SumasenLibs/excel_lib/sumaexcel/styles.py
Normal file
@ -0,0 +1,115 @@
|
||||
# sumaexcel/styles.py
|
||||
from typing import Dict, Any, Optional, Union
|
||||
from openpyxl.styles import (
|
||||
Font, PatternFill, Alignment, Border, Side,
|
||||
NamedStyle, Protection, Color
|
||||
)
|
||||
from openpyxl.styles.differential import DifferentialStyle
|
||||
from openpyxl.formatting.rule import Rule
|
||||
from openpyxl.worksheet.worksheet import Worksheet
|
||||
|
||||
class StyleManager:
|
||||
"""Excel style management class"""
|
||||
|
||||
@staticmethod
|
||||
def create_font(
|
||||
name: str = "Arial",
|
||||
size: int = 11,
|
||||
bold: bool = False,
|
||||
italic: bool = False,
|
||||
color: str = "000000",
|
||||
underline: str = None,
|
||||
strike: bool = False
|
||||
) -> Font:
|
||||
"""Create a Font object with specified parameters"""
|
||||
return Font(
|
||||
name=name,
|
||||
size=size,
|
||||
bold=bold,
|
||||
italic=italic,
|
||||
color=color,
|
||||
underline=underline,
|
||||
strike=strike
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def create_fill(
|
||||
fill_type: str = "solid",
|
||||
start_color: str = "FFFFFF",
|
||||
end_color: str = None
|
||||
) -> PatternFill:
|
||||
"""Create a PatternFill object"""
|
||||
return PatternFill(
|
||||
fill_type=fill_type,
|
||||
start_color=start_color,
|
||||
end_color=end_color or start_color
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def create_border(
|
||||
style: str = "thin",
|
||||
color: str = "000000"
|
||||
) -> Border:
|
||||
"""Create a Border object"""
|
||||
side = Side(style=style, color=color)
|
||||
return Border(
|
||||
left=side,
|
||||
right=side,
|
||||
top=side,
|
||||
bottom=side
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def create_alignment(
|
||||
horizontal: str = "general",
|
||||
vertical: str = "bottom",
|
||||
wrap_text: bool = False,
|
||||
shrink_to_fit: bool = False,
|
||||
indent: int = 0
|
||||
) -> Alignment:
|
||||
"""Create an Alignment object"""
|
||||
return Alignment(
|
||||
horizontal=horizontal,
|
||||
vertical=vertical,
|
||||
wrap_text=wrap_text,
|
||||
shrink_to_fit=shrink_to_fit,
|
||||
indent=indent
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def copy_style(source_cell: Any, target_cell: Any) -> None:
|
||||
"""Copy all style properties from source cell to target cell"""
|
||||
target_cell.font = Font(
|
||||
name=source_cell.font.name,
|
||||
size=source_cell.font.size,
|
||||
bold=source_cell.font.bold,
|
||||
italic=source_cell.font.italic,
|
||||
color=source_cell.font.color,
|
||||
underline=source_cell.font.underline,
|
||||
strike=source_cell.font.strike
|
||||
)
|
||||
|
||||
if source_cell.fill.patternType != None:
|
||||
target_cell.fill = PatternFill(
|
||||
fill_type=source_cell.fill.patternType,
|
||||
start_color=source_cell.fill.start_color.rgb,
|
||||
end_color=source_cell.fill.end_color.rgb
|
||||
)
|
||||
|
||||
target_cell.border = Border(
|
||||
left=source_cell.border.left,
|
||||
right=source_cell.border.right,
|
||||
top=source_cell.border.top,
|
||||
bottom=source_cell.border.bottom
|
||||
)
|
||||
|
||||
target_cell.alignment = Alignment(
|
||||
horizontal=source_cell.alignment.horizontal,
|
||||
vertical=source_cell.alignment.vertical,
|
||||
wrap_text=source_cell.alignment.wrap_text,
|
||||
shrink_to_fit=source_cell.alignment.shrink_to_fit,
|
||||
indent=source_cell.alignment.indent
|
||||
)
|
||||
|
||||
if source_cell.number_format:
|
||||
target_cell.number_format = source_cell.number_format
|
||||
276
SumasenLibs/excel_lib/sumaexcel/sumaexcel.py
Normal file
276
SumasenLibs/excel_lib/sumaexcel/sumaexcel.py
Normal file
@ -0,0 +1,276 @@
|
||||
# sumaexcel/excel.py
|
||||
|
||||
import openpyxl
|
||||
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
|
||||
from openpyxl.utils import get_column_letter
|
||||
import pandas as pd
|
||||
from typing import Optional, Dict, List, Union, Any
|
||||
import os
|
||||
import shutil
|
||||
from datetime import datetime
|
||||
from typing import Optional, Dict, Any, Union, Tuple
|
||||
from pathlib import Path
|
||||
|
||||
from .styles import StyleManager
|
||||
from .merge import MergeManager
|
||||
from .image import ImageManager
|
||||
from .conditional import ConditionalFormatManager
|
||||
from .page import PageManager, PaperSizes
|
||||
|
||||
class SumasenExcel:
|
||||
"""Enhanced Excel handling class with extended functionality"""
|
||||
|
||||
def __init__(self, debug: bool = False):
|
||||
self.debug = debug
|
||||
self.workbook = None
|
||||
self.template_filepath = None
|
||||
self.output_filepath = None
|
||||
self.current_sheet = None
|
||||
|
||||
self._style_manager = None
|
||||
self._merge_manager = None
|
||||
self._image_manager = None
|
||||
self._conditional_manager = None
|
||||
self._page_manager = None
|
||||
|
||||
def init(self, username: str, project_id: str, document: str,
|
||||
lang: str = "jp", docbase: str = "./docbase") -> Dict[str, str]:
|
||||
"""Initialize Excel document with basic settings
|
||||
|
||||
Args:
|
||||
username: User name for file operations
|
||||
project_id: Project identifier
|
||||
document: Document name
|
||||
lang: Language code (default: "jp")
|
||||
docbase: Base directory for documents (default: "./docbase")
|
||||
|
||||
Returns:
|
||||
Dict with status ("ACK"/"NCK") and optional error message
|
||||
"""
|
||||
try:
|
||||
self.username = username
|
||||
self.project_id = project_id
|
||||
self.language = lang
|
||||
|
||||
# Setup directory structure
|
||||
self.docpath = docbase
|
||||
self.docpath2 = f"{docbase}/{project_id}"
|
||||
|
||||
# Create directories if they don't exist
|
||||
for path in [docbase, self.docpath2]:
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path, mode=0o755)
|
||||
|
||||
# Load template
|
||||
inifile = f"{document}.ini"
|
||||
self.inifilepath = f"{self.docpath2}/{inifile}"
|
||||
|
||||
if not os.path.exists(self.inifilepath):
|
||||
return {"status": "NCK", "message": f"INI file not found: {self.inifilepath}"}
|
||||
|
||||
# Load template workbook
|
||||
template_file = self._get_ini_param("basic", f"templatefile_{lang}")
|
||||
self.template_filepath = f"{self.docpath2}/{template_file}"
|
||||
|
||||
if not os.path.exists(self.template_filepath):
|
||||
# Copy from default if not exists
|
||||
default_template = f"{self.docpath}/{template_file}"
|
||||
shutil.copy2(default_template, self.template_filepath)
|
||||
|
||||
self.workbook = openpyxl.load_workbook(self.template_filepath)
|
||||
|
||||
return {"status": "ACK"}
|
||||
|
||||
except Exception as e:
|
||||
return {"status": "NCK", "message": str(e)}
|
||||
|
||||
def _get_ini_param(self, section: str, param: str) -> Optional[str]:
|
||||
"""Get parameter from INI file
|
||||
|
||||
Args:
|
||||
section: INI file section
|
||||
param: Parameter name
|
||||
|
||||
Returns:
|
||||
Parameter value or None if not found
|
||||
"""
|
||||
try:
|
||||
# Use configparser to handle INI files
|
||||
import configparser
|
||||
config = configparser.ConfigParser()
|
||||
config.read(self.inifilepath)
|
||||
return config[section][param]
|
||||
except:
|
||||
return None
|
||||
|
||||
def make_report(self, db, data_rec: Dict[str, Any],
|
||||
out_filename: Optional[str] = None,
|
||||
screen_index: int = 0) -> None:
|
||||
"""Generate Excel report from template
|
||||
|
||||
Args:
|
||||
db: Database connection
|
||||
data_rec: Data records to populate report
|
||||
out_filename: Optional output filename
|
||||
screen_index: Screen index for multi-screen reports
|
||||
"""
|
||||
# Get output filename
|
||||
if out_filename:
|
||||
outfile = f"{out_filename}_{self._get_ini_param('basic', 'doc_file')}"
|
||||
else:
|
||||
outfile = self._get_ini_param('basic', 'doc_file')
|
||||
|
||||
self.output_filepath = f"{self.docpath2}/{outfile}"
|
||||
|
||||
# Process sections
|
||||
sections = self._get_ini_param('basic', 'sections')
|
||||
if not sections:
|
||||
return
|
||||
|
||||
for section in sections.split(','):
|
||||
self._process_section(section, db, data_rec, screen_index)
|
||||
|
||||
# Save workbook
|
||||
self.workbook.save(self.output_filepath)
|
||||
|
||||
def _process_section(self, section: str, db, data_rec: Dict[str, Any],
|
||||
screen_index: int) -> None:
|
||||
"""Process individual section of report
|
||||
|
||||
Args:
|
||||
section: Section name
|
||||
db: Database connection
|
||||
data_rec: Data records
|
||||
screen_index: Screen index
|
||||
"""
|
||||
# Get template sheet
|
||||
sheet_orig = self._get_ini_param(section, 'sheet')
|
||||
sheet_name = self._get_ini_param(section, f"sheetname_{self.language}")
|
||||
|
||||
if not sheet_orig or not sheet_name:
|
||||
return
|
||||
|
||||
# Copy template sheet
|
||||
template_sheet = self.workbook[sheet_orig]
|
||||
new_sheet = self.workbook.copy_worksheet(template_sheet)
|
||||
new_sheet.title = sheet_name
|
||||
|
||||
# Process groups
|
||||
groups = self._get_ini_param(section, 'groups')
|
||||
if groups:
|
||||
for group in groups.split(','):
|
||||
self._process_group(new_sheet, section, group, db, data_rec, screen_index)
|
||||
|
||||
def _process_group(self, sheet, section: str, group: str,
|
||||
db, data_rec: Dict[str, Any], screen_index: int) -> None:
|
||||
"""Process group within section
|
||||
|
||||
Args:
|
||||
sheet: Worksheet to process
|
||||
section: Section name
|
||||
group: Group name
|
||||
db: Database connection
|
||||
data_rec: Data records
|
||||
screen_index: Screen index
|
||||
"""
|
||||
pass # Implementation details will follow
|
||||
|
||||
|
||||
|
||||
|
||||
def init_sheet(self, sheet_name: str) -> None:
|
||||
"""Initialize worksheet and managers"""
|
||||
self.current_sheet = self.workbook[sheet_name]
|
||||
self._style_manager = StyleManager()
|
||||
self._merge_manager = MergeManager(self.current_sheet)
|
||||
self._image_manager = ImageManager(self.current_sheet)
|
||||
self._conditional_manager = ConditionalFormatManager(self.current_sheet)
|
||||
self._page_manager = PageManager(self.current_sheet)
|
||||
|
||||
# Style operations
|
||||
def apply_style(
|
||||
self,
|
||||
cell_range: str,
|
||||
font: Dict[str, Any] = None,
|
||||
fill: Dict[str, Any] = None,
|
||||
border: Dict[str, Any] = None,
|
||||
alignment: Dict[str, Any] = None
|
||||
) -> None:
|
||||
"""Apply styles to cell range"""
|
||||
for row in self.current_sheet[cell_range]:
|
||||
for cell in row:
|
||||
if font:
|
||||
cell.font = self._style_manager.create_font(**font)
|
||||
if fill:
|
||||
cell.fill = self._style_manager.create_fill(**fill)
|
||||
if border:
|
||||
cell.border = self._style_manager.create_border(**border)
|
||||
if alignment:
|
||||
cell.alignment = self._style_manager.create_alignment(**alignment)
|
||||
|
||||
# Merge operations
|
||||
def merge_range(
|
||||
self,
|
||||
start_row: int,
|
||||
start_col: int,
|
||||
end_row: int,
|
||||
end_col: int
|
||||
) -> None:
|
||||
"""Merge cell range"""
|
||||
self._merge_manager.merge_cells(start_row, start_col, end_row, end_col)
|
||||
|
||||
# Image operations
|
||||
def add_image(
|
||||
self,
|
||||
image_path: Union[str, Path],
|
||||
position: Tuple[int, int],
|
||||
size: Optional[Tuple[int, int]] = None
|
||||
) -> None:
|
||||
"""Add image to worksheet"""
|
||||
self._image_manager.add_image(image_path, position, size)
|
||||
|
||||
# Conditional formatting
|
||||
def add_conditional_format(
|
||||
self,
|
||||
cell_range: str,
|
||||
format_type: str,
|
||||
**kwargs
|
||||
) -> None:
|
||||
"""Add conditional formatting"""
|
||||
if format_type == 'color_scale':
|
||||
self._conditional_manager.add_color_scale(cell_range, **kwargs)
|
||||
elif format_type == 'data_bar':
|
||||
self._conditional_manager.add_data_bar(cell_range, **kwargs)
|
||||
elif format_type == 'icon_set':
|
||||
self._conditional_manager.add_icon_set(cell_range, **kwargs)
|
||||
elif format_type == 'custom':
|
||||
self._conditional_manager.add_custom_rule(cell_range, **kwargs)
|
||||
|
||||
# Page setup
|
||||
def setup_page(
|
||||
self,
|
||||
orientation: str = 'portrait',
|
||||
paper_size: int = PaperSizes.A4,
|
||||
margins: Dict[str, float] = None,
|
||||
header_footer: Dict[str, Any] = None
|
||||
) -> None:
|
||||
"""Configure page setup"""
|
||||
self._page_manager.set_page_setup(
|
||||
orientation=orientation,
|
||||
paper_size=paper_size
|
||||
)
|
||||
|
||||
if margins:
|
||||
self._page_manager.set_margins(**margins)
|
||||
|
||||
if header_footer:
|
||||
self._page_manager.set_header_footer(**header_footer)
|
||||
|
||||
def cleanup(self) -> None:
|
||||
"""Cleanup temporary files"""
|
||||
if self._image_manager:
|
||||
self._image_manager.cleanup()
|
||||
|
||||
def __del__(self):
|
||||
"""Destructor"""
|
||||
self.cleanup()
|
||||
55
SumasenLibs/excel_lib/testdata/sample.py
vendored
Normal file
55
SumasenLibs/excel_lib/testdata/sample.py
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
from sumaexcel import SumasenExcel
|
||||
|
||||
# 初期化
|
||||
excel = SumasenExcel()
|
||||
excel.init("username", "project_id", "document")
|
||||
|
||||
# シート初期化
|
||||
excel.init_sheet("Sheet1")
|
||||
|
||||
# スタイル適用
|
||||
excel.apply_style(
|
||||
"A1:D10",
|
||||
font={"name": "Arial", "size": 12, "bold": True},
|
||||
fill={"start_color": "FFFF00"},
|
||||
alignment={"horizontal": "center"}
|
||||
)
|
||||
|
||||
# セルのマージ
|
||||
excel.merge_range(1, 1, 1, 4)
|
||||
|
||||
# 画像追加
|
||||
excel.add_image(
|
||||
"logo.png",
|
||||
position=(1, 1),
|
||||
size=(100, 100)
|
||||
)
|
||||
|
||||
# 条件付き書式
|
||||
excel.add_conditional_format(
|
||||
"B2:B10",
|
||||
format_type="color_scale",
|
||||
min_color="00FF0000",
|
||||
max_color="0000FF00"
|
||||
)
|
||||
|
||||
# ページ設定
|
||||
excel.setup_page(
|
||||
orientation="landscape",
|
||||
paper_size=PaperSizes.A4,
|
||||
margins={
|
||||
"left": 1.0,
|
||||
"right": 1.0,
|
||||
"top": 1.0,
|
||||
"bottom": 1.0
|
||||
},
|
||||
header_footer={
|
||||
"odd_header": "&L&BPage &P of &N&C&BConfidential",
|
||||
"odd_footer": "&RDraft"
|
||||
}
|
||||
)
|
||||
|
||||
# レポート生成
|
||||
excel.make_report(db, data_rec)
|
||||
|
||||
|
||||
25
SumasenLibs/excel_lib/testdata/test.ini
vendored
Normal file
25
SumasenLibs/excel_lib/testdata/test.ini
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
[basic]
|
||||
templatefile_jp="certificate_template.xlsx"
|
||||
doc_file="certificate_[zekken_number].xlsx"
|
||||
sections=section1,section2
|
||||
developer=Sumasen
|
||||
maxcol=8
|
||||
|
||||
[section1]
|
||||
sheet="certificate"
|
||||
sheetname_jp="岐阜ロゲ通過証明書"
|
||||
groups="group1,group2"
|
||||
fit_to_width=1
|
||||
orientation=portrait
|
||||
|
||||
[section1.group1]
|
||||
table_name=rog_entry
|
||||
where="zekken_number='[zekken_number]' and event_code='[event_code]'"
|
||||
group_range="0,0,8,11"
|
||||
|
||||
[section1.group2]
|
||||
table_name=gps_checkins
|
||||
where=""zekken_number='[zekken_number]' and event_code='[event_code]'
|
||||
sort=order
|
||||
group_range=0,12,8,12
|
||||
|
||||
@ -53,10 +53,14 @@ INSTALLED_APPS = [
|
||||
'leaflet',
|
||||
'leaflet_admin_list',
|
||||
'rog.apps.RogConfig',
|
||||
'corsheaders', # added
|
||||
'django_filters'
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'corsheaders.middleware.CorsMiddleware', # できるだけ上部に
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
@ -68,10 +72,47 @@ MIDDLEWARE = [
|
||||
|
||||
ROOT_URLCONF = 'config.urls'
|
||||
|
||||
CORS_ALLOW_ALL_ORIGINS = True # 開発環境のみ
|
||||
CORS_ALLOW_CREDENTIALS = True
|
||||
|
||||
CORS_ALLOWED_METHODS = [
|
||||
'GET',
|
||||
'POST',
|
||||
'PUT',
|
||||
'PATCH',
|
||||
'DELETE',
|
||||
'OPTIONS'
|
||||
]
|
||||
CORS_ALLOWED_HEADERS = [
|
||||
'accept',
|
||||
'accept-encoding',
|
||||
'authorization',
|
||||
'content-type',
|
||||
'dnt',
|
||||
'origin',
|
||||
'user-agent',
|
||||
'x-csrftoken',
|
||||
'x-requested-with',
|
||||
]
|
||||
|
||||
# 本番環境では以下のように制限する
|
||||
CORS_ALLOWED_ORIGINS = [
|
||||
"https://rogaining.sumasen.net",
|
||||
"http://rogaining.sumasen.net",
|
||||
]
|
||||
|
||||
# CSRFの設定
|
||||
CSRF_TRUSTED_ORIGINS = [
|
||||
"http://rogaining.sumasen.net",
|
||||
"https://rogaining.sumasen.net",
|
||||
]
|
||||
|
||||
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [BASE_DIR / 'templates'],
|
||||
'DIRS': [os.path.join(BASE_DIR, 'templates')],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
@ -138,10 +179,12 @@ USE_TZ = True
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
#STATIC_URL = '/static2/'
|
||||
STATIC_ROOT = BASE_DIR / "static"
|
||||
#STATIC_ROOT = BASE_DIR / "static"
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
|
||||
|
||||
MEDIA_URL = '/media/'
|
||||
MEDIA_ROOT = BASE_DIR / "media/"
|
||||
#MEDIA_ROOT = BASE_DIR / "media/"
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||||
|
||||
#STATICFILES_DIRS = (os.path.join(BASE_DIR, "static2"),os.path.join(BASE_DIR, "media"))
|
||||
|
||||
@ -174,3 +217,87 @@ REST_FRAMEWORK = {
|
||||
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': ('knox.auth.TokenAuthentication', ),
|
||||
}
|
||||
|
||||
|
||||
#FRONTEND_URL = 'https://rogaining.intranet.sumasen.net' # フロントエンドのURLに適宜変更してください
|
||||
FRONTEND_URL = 'https://rogaining.sumasen.net' # フロントエンドのURLに適宜変更してください
|
||||
|
||||
# この設定により、メールは実際には送信されず、代わりにコンソールに出力されます。
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
|
||||
EMAIL_HOST = 'smtp.outlook.com'
|
||||
EMAIL_PORT = 587
|
||||
EMAIL_USE_TLS = True
|
||||
EMAIL_HOST_USER = 'rogaining@gifuai.net'
|
||||
EMAIL_HOST_PASSWORD = 'ctcpy9823"x~'
|
||||
DEFAULT_FROM_EMAIL = 'rogaining@gifuai.net'
|
||||
|
||||
APP_DOWNLOAD_LINK = 'https://apps.apple.com/jp/app/%E5%B2%90%E9%98%9C%E3%83%8A%E3%83%93/id6444221792'
|
||||
ANDROID_DOWNLOAD_LINK = 'https://play.google.com/store/apps/details?id=com.dvox.gifunavi&hl=ja'
|
||||
|
||||
SERVICE_NAME = '岐阜ナビ(岐阜ロゲのアプリ)'
|
||||
|
||||
# settings.py
|
||||
DEFAULT_CHARSET = 'utf-8'
|
||||
|
||||
#REST_FRAMEWORK = {
|
||||
# 'DEFAULT_RENDERER_CLASSES': [
|
||||
# 'rest_framework.renderers.JSONRenderer',
|
||||
# ],
|
||||
# 'JSON_UNICODE_ESCAPE': False,
|
||||
#}
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'formatters': {
|
||||
'verbose': {
|
||||
'format': '{levelname} {asctime} {module} {message}',
|
||||
'style': '{',
|
||||
},
|
||||
},
|
||||
'handlers': {
|
||||
#'file': {
|
||||
# 'level': 'DEBUG',
|
||||
# 'class': 'logging.FileHandler',
|
||||
# 'filename': os.path.join(BASE_DIR, 'logs/debug.log'),
|
||||
# 'formatter': 'verbose',
|
||||
#},
|
||||
'console': {
|
||||
'level': 'DEBUG',
|
||||
'class': 'logging.StreamHandler',
|
||||
'formatter': 'verbose',
|
||||
},
|
||||
},
|
||||
'root': {
|
||||
'handlers': ['console'],
|
||||
'level': 'DEBUG',
|
||||
},
|
||||
'loggers': {
|
||||
'django': {
|
||||
'handlers': ['console'],
|
||||
'level': 'INFO',
|
||||
'propagate': False,
|
||||
},
|
||||
'django.request': {
|
||||
'handlers': ['console'],
|
||||
'level': 'DEBUG',
|
||||
},
|
||||
'rog': {
|
||||
#'handlers': ['file','console'],
|
||||
'handlers': ['console'],
|
||||
'level': 'DEBUG',
|
||||
'propagate': True,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
PASSWORD_HASHERS = [
|
||||
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
|
||||
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
|
||||
'django.contrib.auth.hashers.Argon2PasswordHasher',
|
||||
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
|
||||
]
|
||||
|
||||
BLACKLISTED_IPS = ['44.230.58.114'] # ブロックしたい IP アドレスをここにリストとして追加
|
||||
|
||||
|
||||
@ -18,6 +18,21 @@ from django.urls import path, include
|
||||
from django.conf import settings
|
||||
from django.conf.urls.static import static
|
||||
|
||||
|
||||
# debug_urlsビューをrogアプリケーションのviewsからインポート
|
||||
from rog import views as rog_views
|
||||
|
||||
DEBUG = True
|
||||
ALLOWED_HOSTS = ['rogaining.sumasen.net', 'localhost', '127.0.0.1']
|
||||
|
||||
# CORSの設定
|
||||
CORS_ALLOW_ALL_ORIGINS = True
|
||||
CORS_ALLOWED_ORIGINS = [
|
||||
"http://rogaining.sumasen.net",
|
||||
"http://localhost",
|
||||
"http://127.0.0.1",
|
||||
]
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
path('auth/', include('knox.urls')),
|
||||
@ -27,3 +42,8 @@ urlpatterns = [
|
||||
admin.site.site_header = "ROGANING"
|
||||
admin.site.site_title = "Roganing Admin Portal"
|
||||
admin.site.index_title = "Welcome to Roganing Portal"
|
||||
|
||||
# 開発環境での静的ファイル配信
|
||||
if settings.DEBUG:
|
||||
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
|
||||
@ -30,12 +30,41 @@ services:
|
||||
env_file:
|
||||
- .env
|
||||
restart: "on-failure"
|
||||
# depends_on:
|
||||
# - postgres-db
|
||||
networks:
|
||||
- rog-api
|
||||
#entrypoint: ["/app/wait-for.sh", "postgres-db:5432", "--", ""]
|
||||
#command: python3 manage.py runserver 0.0.0.0:8100
|
||||
|
||||
supervisor-web:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.supervisor
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ./supervisor/html
|
||||
target: /usr/share/nginx/html/supervisor
|
||||
read_only: true
|
||||
- type: bind
|
||||
source: ./supervisor/nginx/default.conf
|
||||
target: /etc/nginx/conf.d/default.conf
|
||||
read_only: true
|
||||
- type: volume
|
||||
source: static_volume
|
||||
target: /app/static
|
||||
read_only: true
|
||||
- type: volume
|
||||
source: nginx_logs
|
||||
target: /var/log/nginx
|
||||
- type: bind
|
||||
source: ./media
|
||||
target: /usr/share/nginx/html/media
|
||||
ports:
|
||||
- "80:80"
|
||||
depends_on:
|
||||
- api
|
||||
networks:
|
||||
- rog-api
|
||||
restart: always
|
||||
|
||||
|
||||
|
||||
networks:
|
||||
rog-api:
|
||||
@ -44,3 +73,5 @@ networks:
|
||||
volumes:
|
||||
postgres_data:
|
||||
geoserver-data:
|
||||
static_volume:
|
||||
nginx_logs:
|
||||
|
||||
81
docker-compose.yaml.ssl
Normal file
81
docker-compose.yaml.ssl
Normal file
@ -0,0 +1,81 @@
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
# postgres-db:
|
||||
# image: kartoza/postgis:12.0
|
||||
# ports:
|
||||
# - 5432:5432
|
||||
# volumes:
|
||||
# - postgres_data:/var/lib/postgresql
|
||||
# - ./custom-postgresql.conf:/etc/postgresql/12/main/postgresql.conf
|
||||
# environment:
|
||||
# - POSTGRES_USER=${POSTGRES_USER}
|
||||
# - POSTGRES_PASS=${POSTGRES_PASS}
|
||||
# - POSTGRES_DBNAME=${POSTGRES_DBNAME}
|
||||
# - POSTGRES_MAX_CONNECTIONS=600
|
||||
|
||||
# restart: "on-failure"
|
||||
# networks:
|
||||
# - rog-api
|
||||
|
||||
api:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.gdal
|
||||
command: python3 manage.py runserver 0.0.0.0:8100
|
||||
volumes:
|
||||
- .:/app
|
||||
ports:
|
||||
- 8100:8100
|
||||
env_file:
|
||||
- .env
|
||||
restart: "on-failure"
|
||||
# depends_on:
|
||||
# - postgres-db
|
||||
networks:
|
||||
- rog-api
|
||||
#entrypoint: ["/app/wait-for.sh", "postgres-db:5432", "--", ""]
|
||||
#command: python3 manage.py runserver 0.0.0.0:8100
|
||||
|
||||
supervisor-web:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.supervisor
|
||||
volumes:
|
||||
- type: bind
|
||||
source: /etc/letsencrypt
|
||||
target: /etc/nginx/ssl
|
||||
read_only: true
|
||||
- type: bind
|
||||
source: ./supervisor/html
|
||||
target: /usr/share/nginx/html
|
||||
read_only: true
|
||||
- type: bind
|
||||
source: ./supervisor/nginx/default.conf
|
||||
target: /etc/nginx/conf.d/default.conf
|
||||
read_only: true
|
||||
- type: volume
|
||||
source: static_volume
|
||||
target: /app/static
|
||||
read_only: true
|
||||
- type: volume
|
||||
source: nginx_logs
|
||||
target: /var/log/nginx
|
||||
ports:
|
||||
- "80:80"
|
||||
depends_on:
|
||||
- api
|
||||
networks:
|
||||
- rog-api
|
||||
restart: always
|
||||
|
||||
|
||||
networks:
|
||||
rog-api:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
geoserver-data:
|
||||
static_volume:
|
||||
nginx_logs:
|
||||
1
dump_rog_data.sql
Normal file
1
dump_rog_data.sql
Normal file
@ -0,0 +1 @@
|
||||
pg_dump: error: connection to database "rogdb" failed: FATAL: Peer authentication failed for user "postgres"
|
||||
10
entrypoint.sh
Normal file
10
entrypoint.sh
Normal file
@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Collect static files
|
||||
python manage.py collectstatic --noinput
|
||||
|
||||
# Apply database migrations
|
||||
python manage.py migrate
|
||||
|
||||
# Start Gunicorn
|
||||
exec "$@"
|
||||
14
nginx.conf
14
nginx.conf
@ -29,17 +29,21 @@ http {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
# 静的ファイルの提供
|
||||
location /static/ {
|
||||
alias /app/static/;
|
||||
}
|
||||
|
||||
location /media/ {
|
||||
alias /app/media/;
|
||||
# スーパーバイザー Web アプリケーション
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
|
||||
location / {
|
||||
proxy_pass http://app:8000;
|
||||
# Django API プロキシ
|
||||
location /api/ {
|
||||
proxy_pass http://api:8000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
@ -65,3 +65,4 @@ django-extra-fields==3.0.2
|
||||
django-phonenumber-field==6.1.0
|
||||
django-rest-knox==4.2.0
|
||||
dj-database-url==2.0.0
|
||||
django-cors-headers==4.3.0
|
||||
|
||||
777
rog/admin.py
777
rog/admin.py
@ -1,16 +1,618 @@
|
||||
import email
|
||||
from django.contrib import admin
|
||||
from django.shortcuts import render
|
||||
from django.shortcuts import render,redirect
|
||||
from leaflet.admin import LeafletGeoAdmin
|
||||
from leaflet.admin import LeafletGeoAdminMixin
|
||||
from leaflet_admin_list.admin import LeafletAdminListMixin
|
||||
from .models import RogUser, Location, SystemSettings, JoinedEvent, Favorite, TravelList, TravelPoint, ShapeLayers, Event, Location_line, Location_polygon, JpnAdminMainPerf, Useractions, CustomUser, GifuAreas, UserTracks, templocation, UserUpload, EventUser, GoalImages, CheckinImages
|
||||
from .models import RogUser, Location, SystemSettings, JoinedEvent, Favorite, TravelList, TravelPoint, ShapeLayers, Event, Location_line, Location_polygon, JpnAdminMainPerf, Useractions, CustomUser, GifuAreas, UserTracks, templocation, UserUpload, EventUser, GoalImages, CheckinImages, NewEvent2, Team, NewCategory, Entry, Member, TempUser,GifurogeRegister
|
||||
from django.contrib.auth.admin import UserAdmin
|
||||
from django.urls import path
|
||||
from django.urls import path,reverse
|
||||
from django.shortcuts import render
|
||||
from django import forms;
|
||||
import requests
|
||||
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.utils.html import format_html
|
||||
from .forms import CSVUploadForm
|
||||
from .views import process_csv_upload
|
||||
|
||||
from django.db.models import F # F式をインポート
|
||||
from django.db import transaction
|
||||
from django.contrib import messages
|
||||
import csv
|
||||
from io import StringIO,TextIOWrapper
|
||||
from datetime import timedelta
|
||||
from django.contrib.auth.hashers import make_password
|
||||
from datetime import datetime, date
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
@admin.register(GifurogeRegister)
|
||||
class GifurogeRegisterAdmin(admin.ModelAdmin):
|
||||
list_display = ('event_code', 'time', 'owner_name', 'email', 'team_name', 'department')
|
||||
change_list_template = 'admin/rog/gifurogeregister/change_list.html' # この行を追加
|
||||
|
||||
def find_matching_category(self, time, department):
|
||||
"""
|
||||
時間とdepartmentに基づいて適切なカテゴリを見つける
|
||||
"""
|
||||
try:
|
||||
duration = timedelta(hours=time)
|
||||
|
||||
# 検索前の情報出力
|
||||
print(f" Searching for category with parameters:")
|
||||
print(f" - Duration: {duration}")
|
||||
print(f" - Department: {department}")
|
||||
|
||||
# 利用可能なカテゴリの一覧を出力
|
||||
all_categories = NewCategory.objects.all()
|
||||
print(" Available categories:")
|
||||
for cat in all_categories:
|
||||
#print(f" - ID: {cat.id}")
|
||||
print(f" - Name: {cat.category_name}")
|
||||
print(f" - Duration: {cat.duration}")
|
||||
print(f" - Number: {cat.category_number}")
|
||||
|
||||
# カテゴリ検索のクエリをログ出力
|
||||
query = NewCategory.objects.filter(
|
||||
duration=duration,
|
||||
category_name__startswith=department
|
||||
)
|
||||
print(f" Query SQL: {query.query}")
|
||||
|
||||
# 検索結果の取得
|
||||
category = query.first()
|
||||
|
||||
if category:
|
||||
print(f" Found matching category:")
|
||||
print(f" - Name: {category.category_name}")
|
||||
print(f" - Duration: {category.duration}")
|
||||
print(f" - Category Number: {getattr(category, 'category_number', 'N/A')}")
|
||||
|
||||
else:
|
||||
print(" No matching category found with the following filters:")
|
||||
print(f" - Duration equals: {duration}")
|
||||
print(f" - Category name starts with: {department}")
|
||||
|
||||
return category
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error finding category: {e}")
|
||||
print(f"Exception type: {type(e)}")
|
||||
import traceback
|
||||
print(f"Traceback: {traceback.format_exc()}")
|
||||
return None
|
||||
|
||||
def create_entry_with_number(self, team, category, owner, event):
|
||||
"""
|
||||
カテゴリ番号をインクリメントしてエントリーを作成
|
||||
"""
|
||||
try:
|
||||
with transaction.atomic():
|
||||
# 事前バリデーション
|
||||
try:
|
||||
# チームメンバーの性別をチェック
|
||||
if category.female:
|
||||
for member in team.members.all():
|
||||
|
||||
print(f" Check existing member {member.user.lastname} {member.user.firstname} female:{member.user.female}")
|
||||
if not member.user.female:
|
||||
raise ValidationError(f"チーム '{team.team_name}' に男性メンバーが含まれているため、"
|
||||
f"カテゴリー '{category.category_name}' には参加できません。")
|
||||
except ValidationError as e:
|
||||
print(f"Pre-validation error: {str(e)}")
|
||||
raise
|
||||
|
||||
# カテゴリを再度ロックして取得
|
||||
category_for_update = NewCategory.objects.select_for_update().get(
|
||||
category_name=category.category_name
|
||||
)
|
||||
|
||||
print(f" Creating entry with following details:")
|
||||
print(f" - Category: {category_for_update.category_name}")
|
||||
print(f" - Current category number: {category_for_update.category_number}")
|
||||
|
||||
# イベントの日付を取得
|
||||
entry_date = event.start_datetime.date()
|
||||
|
||||
# 既存のエントリーをチェック
|
||||
existing_entry = Entry.objects.filter(
|
||||
team=team,
|
||||
event=event,
|
||||
date=entry_date,
|
||||
is_active=True # アクティブなエントリーのみをチェック
|
||||
).first()
|
||||
|
||||
if existing_entry:
|
||||
print(f" Found existing entry for team {team.team_name} on {entry_date}")
|
||||
raise ValidationError(
|
||||
f"Team {team.team_name} already has an entry for event {event.event_name} on {entry_date}"
|
||||
)
|
||||
|
||||
# 現在の番号を取得してインクリメント
|
||||
current_number = category_for_update.category_number
|
||||
zekken_number = current_number
|
||||
|
||||
# カテゴリ番号をインクリメント
|
||||
category_for_update.category_number = F('category_number') + 1
|
||||
category_for_update.save()
|
||||
|
||||
# 変更後の値を取得して表示
|
||||
category_for_update.refresh_from_db()
|
||||
print(f" Updated category number: {category_for_update.category_number}")
|
||||
|
||||
# エントリーの作成
|
||||
try:
|
||||
entry = Entry.objects.create(
|
||||
date=event.start_datetime,
|
||||
team=team,
|
||||
category=category,
|
||||
owner=owner,
|
||||
event=event,
|
||||
zekken_number=zekken_number,
|
||||
is_active=True
|
||||
)
|
||||
# バリデーションを実行
|
||||
entry.full_clean()
|
||||
# 問題なければ保存
|
||||
entry.save()
|
||||
|
||||
print(f" Created entry:")
|
||||
print(f" - Team: {team.team_name}")
|
||||
print(f" - Event: {event.event_name}")
|
||||
print(f" - Category: {category.category_name}")
|
||||
print(f" - Zekken Number: {zekken_number}")
|
||||
|
||||
return entry
|
||||
|
||||
except ValidationError as e:
|
||||
print(f"Entry validation error: {str(e)}")
|
||||
raise
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error creating entry: {e}")
|
||||
print(f"Exception type: {type(e)}")
|
||||
import traceback
|
||||
print(f"Traceback: {traceback.format_exc()}")
|
||||
raise
|
||||
|
||||
def split_full_name(self, full_name):
|
||||
"""
|
||||
フルネームを姓と名に分割
|
||||
半角または全角スペースに対応
|
||||
"""
|
||||
try:
|
||||
# 空白文字で分割(半角スペース、全角スペース、タブなど)
|
||||
parts = full_name.replace(' ', ' ').split()
|
||||
if len(parts) >= 2:
|
||||
last_name = parts[0]
|
||||
first_name = ' '.join(parts[1:]) # 名が複数単語の場合に対応
|
||||
return last_name, first_name
|
||||
else:
|
||||
# 分割できない場合は全体を姓とする
|
||||
return full_name, ''
|
||||
except Exception as e:
|
||||
print(f"Error splitting name '{full_name}': {e}")
|
||||
return full_name, ''
|
||||
|
||||
def convert_japanese_date(self, date_text):
|
||||
"""
|
||||
日本式の日付テキストをDateField形式に変換
|
||||
例: '1990年1月1日' -> datetime.date(1990, 1, 1)
|
||||
"""
|
||||
try:
|
||||
if not date_text or date_text.strip() == '':
|
||||
return None
|
||||
|
||||
# 全角数字を半角数字に変換
|
||||
date_text = date_text.translate(str.maketrans('0123456789', '0123456789'))
|
||||
date_text = date_text.strip()
|
||||
|
||||
# 区切り文字の判定と分割
|
||||
if '年' in date_text:
|
||||
# 年月日形式の場合
|
||||
date_parts = date_text.replace('年', '-').replace('月', '-').replace('日', '').split('-')
|
||||
elif '/' in date_text:
|
||||
# スラッシュ区切りの場合
|
||||
date_parts = date_text.split('/')
|
||||
elif '-' in date_text:
|
||||
date_parts = date_text.split('-')
|
||||
else:
|
||||
print(f"Unsupported date format: {date_text}")
|
||||
return None
|
||||
|
||||
# 部分の数を確認
|
||||
if len(date_parts) != 3:
|
||||
print(f"Invalid date parts count: {len(date_parts)} in '{date_text}'")
|
||||
return None
|
||||
|
||||
year = int(date_parts[0])
|
||||
month = int(date_parts[1])
|
||||
day = int(date_parts[2])
|
||||
|
||||
# 簡単な妥当性チェック
|
||||
if not (1900 <= year <= 2100):
|
||||
print(f"Invalid year: {year}")
|
||||
return None
|
||||
if not (1 <= month <= 12):
|
||||
print(f"Invalid month: {month}")
|
||||
return None
|
||||
if not (1 <= day <= 31): # 月ごとの日数チェックは省略
|
||||
print(f"Invalid day: {day}")
|
||||
return None
|
||||
|
||||
print(f"Converted from {date_text} to year-{year} / month-{month} / day-{day}")
|
||||
|
||||
return date(year, month, day)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error converting date '{date_text}': {str(e)}")
|
||||
return None
|
||||
|
||||
def create_owner_member( self,team,row ):
|
||||
"""
|
||||
オーナーをチームメンバー1として作成
|
||||
既存のメンバーは更新
|
||||
"""
|
||||
try:
|
||||
owner_name = row.get('owner_name').strip()
|
||||
# 姓名を分割
|
||||
last_name, first_name = self.split_full_name(owner_name)
|
||||
print(f" Split name - Last: {last_name}, First: {first_name}")
|
||||
# 誕生日の処理
|
||||
birthday = row.get(f'owner_birthday', '').strip()
|
||||
birth_date = self.convert_japanese_date(birthday)
|
||||
print(f" Converted birthday: {birth_date}")
|
||||
|
||||
# 性別の処理
|
||||
sex = row.get(f'owner_sex', '').strip()
|
||||
is_female = sex in ['女性','女','女子','female','girl','lady']
|
||||
print(f" Sex: {sex}, is_female: {is_female}")
|
||||
|
||||
# メンバーを作成
|
||||
member,created = Member.objects.get_or_create(
|
||||
team=team,
|
||||
user=team.owner,
|
||||
defaults={
|
||||
'is_temporary': True # 仮登録
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
# 既存メンバーの場合は情報を更新
|
||||
if not created:
|
||||
member.lastname = last_name
|
||||
member.firstname = first_name
|
||||
member.date_of_birth = birth_date
|
||||
member.female = is_female
|
||||
member.is_temporary = True
|
||||
member.save()
|
||||
print(f" Updated existing member {last_name} {first_name}")
|
||||
else:
|
||||
print(f" Created new member {last_name} {first_name}")
|
||||
|
||||
return member
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error creating/updating member: {e}")
|
||||
raise
|
||||
|
||||
def create_members(self, team, row):
|
||||
"""
|
||||
チームのメンバーを作成
|
||||
既存のメンバーは更新
|
||||
"""
|
||||
try:
|
||||
created_members = []
|
||||
|
||||
# オーナーをメンバーに登録
|
||||
member = self.create_owner_member(team,row)
|
||||
created_members.append(member)
|
||||
|
||||
# メンバー2から5までを処理
|
||||
for i in range(2, 6):
|
||||
member_name = row.get(f'member{i}', '').strip()
|
||||
if member_name:
|
||||
print(f"===== Processing member: {member_name} =====")
|
||||
|
||||
# 姓名を分割
|
||||
last_name, first_name = self.split_full_name(member_name)
|
||||
print(f" Split name - Last: {last_name}, First: {first_name}")
|
||||
|
||||
# 誕生日の処理
|
||||
birthday = row.get(f'birthday{i}', '').strip()
|
||||
birth_date = self.convert_japanese_date(birthday)
|
||||
print(f" Converted birthday: {birth_date}")
|
||||
|
||||
# 性別の処理
|
||||
sex = row.get(f'sex{i}', '').strip()
|
||||
is_female = sex in ['女性','女','女子','female','girl','lady']
|
||||
print(f" Sex: {sex}, is_female: {is_female}")
|
||||
|
||||
# メンバー用のユーザーを作成
|
||||
email = f"dummy_{team.id}_{i}@gifuai.net".lower()
|
||||
member_user, created = CustomUser.objects.get_or_create(
|
||||
email=email,
|
||||
defaults={
|
||||
'password': make_password('temporary_password'),
|
||||
'lastname': last_name,
|
||||
'firstname': first_name,
|
||||
'date_of_birth': birth_date,
|
||||
'female':is_female
|
||||
}
|
||||
)
|
||||
|
||||
# 既存ユーザーの場合も姓名を更新
|
||||
if not created:
|
||||
member_user.lastname = last_name
|
||||
member_user.firstname = first_name
|
||||
member_user.date_of_birth = birth_date
|
||||
member_user.female = is_female
|
||||
member_user.save()
|
||||
|
||||
try:
|
||||
# メンバーを作成
|
||||
member,created = Member.objects.get_or_create(
|
||||
team=team,
|
||||
user=member_user,
|
||||
defaults={
|
||||
'is_temporary': True # 仮登録
|
||||
}
|
||||
)
|
||||
|
||||
# 既存メンバーの場合は情報を更新
|
||||
if not created:
|
||||
member.is_temporary = True
|
||||
member.save()
|
||||
print(f" Updated existing member {member_user.lastname} {member_user.firstname}")
|
||||
else:
|
||||
print(f" Created new member {member_user.lastname} {member_user.firstname}")
|
||||
|
||||
created_members.append(member)
|
||||
print(f" - Birthday: {member_user.date_of_birth}")
|
||||
print(f" - Sex: {'Female' if member_user.female else 'Male'}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error creating/updating member: {e}")
|
||||
raise
|
||||
|
||||
return created_members
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error creating members: {e}")
|
||||
print(f"Exception type: {type(e)}")
|
||||
import traceback
|
||||
print(f"Traceback: {traceback.format_exc()}")
|
||||
raise
|
||||
|
||||
def get_urls(self):
|
||||
urls = super().get_urls()
|
||||
custom_urls = [
|
||||
path('upload-csv/', self.upload_csv, name='gifuroge_register_upload_csv'),
|
||||
]
|
||||
return custom_urls + urls
|
||||
|
||||
def upload_csv(self, request):
|
||||
print("upload_csv")
|
||||
if request.method == 'POST':
|
||||
print("POST")
|
||||
if 'csv_file' not in request.FILES:
|
||||
messages.error(request, 'No file was uploaded.')
|
||||
return redirect('..')
|
||||
|
||||
csv_file = request.FILES['csv_file']
|
||||
print(f"csv_file(1) = {csv_file}")
|
||||
if not csv_file.name.endswith('.csv'):
|
||||
messages.error(request, 'File is not CSV type')
|
||||
return redirect('..')
|
||||
|
||||
try:
|
||||
# BOMを考慮してファイルを読み込む
|
||||
file_content = csv_file.read()
|
||||
# BOMがある場合は除去
|
||||
if file_content.startswith(b'\xef\xbb\xbf'):
|
||||
file_content = file_content[3:]
|
||||
|
||||
# デコード
|
||||
file_content = file_content.decode('utf-8')
|
||||
csv_file = StringIO(file_content)
|
||||
reader = csv.DictReader(csv_file)
|
||||
|
||||
print(f"csv_file(2) = {csv_file}")
|
||||
print(f"reader = {reader}")
|
||||
|
||||
with transaction.atomic():
|
||||
for row in reader:
|
||||
print(f" row={row}")
|
||||
|
||||
# オーナーの姓名を分割
|
||||
owner_lastname, owner_firstname = self.split_full_name(row['owner_name'])
|
||||
|
||||
# パスワードをハッシュ化
|
||||
hashed_password = make_password(row['password'])
|
||||
|
||||
# オーナーの誕生日の処理
|
||||
owner_birthday = row.get('owner_birthday', '').strip()
|
||||
owner_birth_date = self.convert_japanese_date(owner_birthday)
|
||||
print(f" Owner birthday: {owner_birth_date}")
|
||||
|
||||
# オーナーの性別の処理
|
||||
owner_sex = row.get('owner_sex', '').strip()
|
||||
owner_is_female = owner_sex in ['女性','女','女子','female','girl','lady']
|
||||
print(f" Owner sex: {owner_sex}, is_female: {owner_is_female}")
|
||||
|
||||
# ユーザーの取得または作成
|
||||
user, created = CustomUser.objects.get_or_create(
|
||||
email=row['email'],
|
||||
defaults={
|
||||
'password': hashed_password, # make_password(row['password'])
|
||||
'lastname': owner_lastname,
|
||||
'firstname': owner_firstname,
|
||||
'date_of_birth': owner_birth_date,
|
||||
'female': owner_is_female
|
||||
}
|
||||
)
|
||||
|
||||
if not created:
|
||||
# 既存ユーザーの場合、空のフィールドがあれば更新
|
||||
should_update = False
|
||||
update_fields = []
|
||||
|
||||
print(f" Checking existing user data for {user.email}:")
|
||||
print(f" - Current lastname: '{user.lastname}'")
|
||||
print(f" - Current firstname: '{user.firstname}'")
|
||||
print(f" - Current birth date: {user.date_of_birth}")
|
||||
print(f" - Current female: {user.female}")
|
||||
|
||||
# 姓が空またはNoneの場合
|
||||
if not user.lastname or user.lastname.strip() == '':
|
||||
user.lastname = owner_lastname
|
||||
should_update = True
|
||||
update_fields.append('lastname')
|
||||
print(f" - Updating lastname to: {owner_lastname}")
|
||||
|
||||
# 名が空またはNoneの場合
|
||||
if not user.firstname or user.firstname.strip() == '':
|
||||
user.firstname = owner_firstname
|
||||
should_update = True
|
||||
update_fields.append('firstname')
|
||||
print(f" - Updating firstname to: {owner_firstname}")
|
||||
|
||||
# 生年月日が空またはNoneの場合
|
||||
if not user.date_of_birth and owner_birth_date:
|
||||
user.date_of_birth = owner_birth_date
|
||||
should_update = True
|
||||
update_fields.append('date_of_birth')
|
||||
print(f" - Updating birth date to: {owner_birth_date}")
|
||||
|
||||
# 性別が空またはNoneの場合
|
||||
# Booleanフィールドなのでis None で判定
|
||||
if user.female is None:
|
||||
user.female = owner_is_female
|
||||
should_update = True
|
||||
update_fields.append('female')
|
||||
print(f" - Updating female to: {owner_is_female}")
|
||||
|
||||
# パスワードが'登録済み'でない場合のみ更新
|
||||
if row['password'] != '登録済み':
|
||||
user.password = hashed_password
|
||||
should_update = True
|
||||
update_fields.append('password')
|
||||
print(f" - Updating password")
|
||||
|
||||
# 変更があった場合のみ保存
|
||||
if should_update:
|
||||
try:
|
||||
# 特定のフィールドのみを更新
|
||||
user.save(update_fields=update_fields)
|
||||
print(f" Updated user {user.email} fields: {', '.join(update_fields)}")
|
||||
except Exception as e:
|
||||
print(f" Error updating user {user.email}: {str(e)}")
|
||||
raise
|
||||
else:
|
||||
print(f" No updates needed for user {user.email}")
|
||||
|
||||
|
||||
print(f" user created...")
|
||||
print(f" Owner member created: {user.lastname} {user.firstname}")
|
||||
print(f" - Birthday: {user.date_of_birth}")
|
||||
print(f" - Sex: {'Female' if user.female else 'Male'}")
|
||||
|
||||
# 適切なカテゴリを見つける
|
||||
category = self.find_matching_category(
|
||||
time=int(row['time']),
|
||||
department=row['department']
|
||||
)
|
||||
|
||||
if not category:
|
||||
raise ValueError(
|
||||
f"No matching category found for time={row['time']} minutes "
|
||||
f"and department={row['department']}"
|
||||
)
|
||||
|
||||
print(f" Using category: {category.category_name}")
|
||||
|
||||
# Teamの作成(既存のチームがある場合は取得)
|
||||
team, created = Team.objects.get_or_create(
|
||||
team_name=row['team_name'],
|
||||
defaults={
|
||||
'owner': user,
|
||||
'category': category
|
||||
}
|
||||
)
|
||||
|
||||
# 既存のチームの場合でもカテゴリを更新
|
||||
if not created:
|
||||
team.category = category
|
||||
team.save()
|
||||
|
||||
print(" team created/updated...")
|
||||
|
||||
self.create_members(team, row)
|
||||
|
||||
# イベントの検索
|
||||
try:
|
||||
event_code = row['event_code']
|
||||
event = NewEvent2.objects.get(event_name=event_code)
|
||||
print(f" Found event: {event.event_name}")
|
||||
except NewEvent2.DoesNotExist:
|
||||
raise ValueError(f"Event with code {event_code} does not exist")
|
||||
|
||||
try:
|
||||
# エントリーの作成
|
||||
entry = self.create_entry_with_number(
|
||||
team=team,
|
||||
category=category,
|
||||
owner=user,
|
||||
event=event,
|
||||
)
|
||||
|
||||
print(" entry created...")
|
||||
except ValidationError as e:
|
||||
messages.error(request, str(e))
|
||||
return redirect('..')
|
||||
|
||||
gifuroge_register = GifurogeRegister.objects.create(
|
||||
event_code=row['event_code'],
|
||||
time=int(row['time']),
|
||||
owner_name_kana=row['owner_name_kana'],
|
||||
owner_name=row['owner_name'],
|
||||
owner_birthday=self.convert_japanese_date(row['owner_birthday']),
|
||||
owner_sex=row['owner_sex'],
|
||||
email=row['email'],
|
||||
password=row['password'],
|
||||
team_name=row['team_name'],
|
||||
department=row['department'],
|
||||
members_count=int(row['members_count']),
|
||||
member2=row.get('member2', '') or None,
|
||||
birthday2=self.convert_japanese_date(row.get('birthday2', '') ),
|
||||
sex2=row.get('sex2', '') or None,
|
||||
member3=row.get('member3', '') or None,
|
||||
birthday3=self.convert_japanese_date(row.get('birthday3', '') ),
|
||||
sex3=row.get('sex3', '') or None,
|
||||
member4=row.get('member4', '') or None,
|
||||
birthday4=self.convert_japanese_date(row.get('birthday4', '') ),
|
||||
sex4=row.get('sex4', '') or None,
|
||||
member5=row.get('member5', '') or None,
|
||||
birthday5=self.convert_japanese_date(row.get('birthday5', '') ),
|
||||
sex5=row.get('sex5', '') or None
|
||||
)
|
||||
print(f" saved gifuroge_register...")
|
||||
|
||||
except UnicodeDecodeError:
|
||||
messages.error(request, 'File encoding error. Please ensure the file is UTF-8 encoded.')
|
||||
return redirect('..')
|
||||
except Exception as e:
|
||||
print(f"Error processing row: {e}")
|
||||
raise
|
||||
|
||||
messages.success(request, 'CSV file uploaded successfully')
|
||||
return redirect('..')
|
||||
|
||||
return render(request, 'admin/rog/gifurogeregister/upload-csv.html')
|
||||
|
||||
class RogAdmin(LeafletAdminListMixin, LeafletGeoAdminMixin, admin.ModelAdmin):
|
||||
list_display=['title', 'venue', 'at_date',]
|
||||
|
||||
@ -53,21 +655,25 @@ class UserAdminConfig(UserAdmin):
|
||||
print("-------Event code--------")
|
||||
for i in data:
|
||||
_exist = CustomUser.objects.filter(email=i["zekken_number"]).delete()
|
||||
other_fields.setDefaut('zekken_number',i['zekken_number'])
|
||||
other_fields.setdefault('is_staff', True)
|
||||
other_fields.setdefault('is_superuser', False)
|
||||
other_fields.setdefault('is_active', True)
|
||||
other_fields.setdefault('event_code', i['event_code'])
|
||||
other_fields.setdefault('team_name', i['team_name'])
|
||||
other_fields.setdefault('group', '大垣-初心者')
|
||||
|
||||
usr = CustomUser.objects.create_user(
|
||||
email=i["zekken_number"],
|
||||
zekken_number=i['zekken_number'],
|
||||
is_rogaining=True,
|
||||
event_code=i['event_code'],
|
||||
team_name=i['team_name'],
|
||||
group='大垣-初心者',
|
||||
password=i['password'],
|
||||
is_staff= True
|
||||
**other_fields
|
||||
)
|
||||
|
||||
form = loadUserForm()
|
||||
data = {'form': form}
|
||||
return render(request, 'admin/load_users.html', data)
|
||||
|
||||
"""
|
||||
fieldsets = (
|
||||
(None, {'fields':('email', 'group', 'zekken_number', 'event_code', 'team_name',)}),
|
||||
('Permissions', {'fields':('is_staff', 'is_active', 'is_rogaining')}),
|
||||
@ -76,6 +682,35 @@ class UserAdminConfig(UserAdmin):
|
||||
add_fieldsets = (
|
||||
(None, {'classes':('wide',), 'fields':('email', 'group','zekken_number', 'event_code', 'team_name', 'password1', 'password2')}),
|
||||
)
|
||||
"""
|
||||
# readonly_fieldsを明示的に設定
|
||||
readonly_fields = ('date_joined',) # 変更不可のフィールドのみを指定=>Personal Infoも編集可能にする。
|
||||
|
||||
fieldsets = (
|
||||
(None, {'fields': ('email', 'password')}),
|
||||
(_('Personal info'), {
|
||||
'fields': ('firstname', 'lastname', 'date_of_birth', 'female'),
|
||||
'classes': ('wide',) # フィールドの表示を広げる
|
||||
}),
|
||||
(_('Permissions'), {'fields': ('is_staff', 'is_active', 'is_rogaining','user_permissions')}),
|
||||
(_('Rogaining info'), {
|
||||
'fields': ('zekken_number', 'event_code', 'team_name', 'group'),
|
||||
'classes': ('wide',)
|
||||
}),
|
||||
(_('Important dates'), {
|
||||
'fields': ('date_joined','last_login'),
|
||||
'classes': ('wide',)
|
||||
}), # 読み取り専用
|
||||
)
|
||||
add_fieldsets = (
|
||||
(None, {
|
||||
'classes': ('wide',),
|
||||
#'fields': ('email', 'password1', 'password2', 'is_staff', 'is_active', 'is_rogaining')}
|
||||
'fields': ('email', 'password1', 'password2', 'lastname','firstname', 'date_of_birth', 'female','is_staff', 'is_active', 'is_rogaining')}
|
||||
),
|
||||
)
|
||||
search_fields = ('email', 'firstname', 'lastname', 'zekken_number', 'team_name')
|
||||
ordering = ('email',)
|
||||
|
||||
class JpnSubPerfAdmin(LeafletGeoAdmin):
|
||||
search_fields = ('adm0_ja', 'adm1_ja', 'adm2_ja', 'name_modified', 'area_name',)
|
||||
@ -194,6 +829,126 @@ class TempLocationAdmin(LeafletGeoAdmin):
|
||||
actions = [tranfer_to_location,]
|
||||
|
||||
|
||||
@admin.register(NewEvent2)
|
||||
class NewEvent2Admin(admin.ModelAdmin):
|
||||
list_display = ['event_name', 'start_datetime', 'end_datetime', 'csv_upload_button']
|
||||
|
||||
def get_urls(self):
|
||||
urls = super().get_urls()
|
||||
my_urls = [
|
||||
path('csv-upload/', self.admin_site.admin_view(self.csv_upload_view), name='newevent2_csv_upload'),
|
||||
]
|
||||
return my_urls + urls
|
||||
|
||||
def csv_upload_view(self, request):
|
||||
if request.method == 'POST':
|
||||
form = CSVUploadForm(request.POST, request.FILES)
|
||||
if form.is_valid():
|
||||
csv_file = request.FILES['csv_file']
|
||||
event = form.cleaned_data['event']
|
||||
process_csv_upload(csv_file, event)
|
||||
self.message_user(request, "CSV file has been processed successfully.")
|
||||
return HttpResponseRedirect("../")
|
||||
else:
|
||||
form = CSVUploadForm()
|
||||
|
||||
return render(request, 'admin/csv_upload.html', {'form': form})
|
||||
|
||||
def csv_upload_button(self, obj):
|
||||
url = reverse('admin:newevent2_csv_upload')
|
||||
return format_html('<a class="button" href="{}">CSVアップロード</a>', url)
|
||||
csv_upload_button.short_description = 'CSV Upload'
|
||||
|
||||
def changelist_view(self, request, extra_context=None):
|
||||
extra_context = extra_context or {}
|
||||
extra_context['csv_upload_url'] = reverse('admin:newevent2_csv_upload')
|
||||
return super().changelist_view(request, extra_context=extra_context)
|
||||
|
||||
|
||||
@admin.register(Team)
|
||||
class TeamAdmin(admin.ModelAdmin):
|
||||
list_display = ['team_name', 'owner']
|
||||
search_fields = ['team_name', 'owner__email']
|
||||
|
||||
@admin.register(NewCategory)
|
||||
class NewCategoryAdmin(admin.ModelAdmin):
|
||||
list_display = ['category_name', 'category_number', 'duration', 'num_of_member', 'family', 'female']
|
||||
list_filter = ['family', 'female']
|
||||
search_fields = ['category_name']
|
||||
|
||||
@admin.register(Entry)
|
||||
class EntryAdmin(admin.ModelAdmin):
|
||||
list_display = ['team', 'event', 'category', 'date']
|
||||
list_filter = ['event', 'category']
|
||||
search_fields = ['team__team_name', 'event__event_name']
|
||||
|
||||
@admin.register(Member)
|
||||
class MemberAdmin(admin.ModelAdmin):
|
||||
list_display = ['team', 'user']
|
||||
search_fields = ['team__team_name', 'user__email']
|
||||
|
||||
@admin.register(TempUser)
|
||||
class TempUserAdmin(admin.ModelAdmin):
|
||||
list_display = ['email', 'is_rogaining', 'zekken_number', 'event_code', 'team_name', 'group', 'created_at', 'expires_at']
|
||||
list_filter = ['is_rogaining', 'group']
|
||||
search_fields = ['email', 'zekken_number', 'team_name']
|
||||
|
||||
|
||||
# CustomUserAdmin の修正(既存のものを更新)
|
||||
class CustomUserChangeForm(UserChangeForm):
|
||||
class Meta(UserChangeForm.Meta):
|
||||
model = CustomUser
|
||||
fields = '__all__'
|
||||
|
||||
class CustomUserCreationForm(UserCreationForm):
|
||||
class Meta(UserCreationForm.Meta):
|
||||
model = CustomUser
|
||||
fields = ('email', 'lastname', 'firstname', 'date_of_birth', 'female')
|
||||
|
||||
class CustomUserAdmin(UserAdmin):
|
||||
form = CustomUserChangeForm
|
||||
add_form = CustomUserCreationForm
|
||||
model = CustomUser
|
||||
|
||||
list_display = ('email', 'is_staff', 'is_active', 'is_rogaining', 'zekken_number', 'event_code', 'team_name', 'group', 'firstname', 'lastname')
|
||||
list_filter = ('is_staff', 'is_active', 'is_rogaining', 'group')
|
||||
|
||||
# readonly_fieldsを明示的に設定
|
||||
readonly_fields = ('date_joined',) # 変更不可のフィールドのみを指定=>Personal Infoも編集可能にする。
|
||||
|
||||
fieldsets = (
|
||||
(None, {'fields': ('email', 'password')}),
|
||||
(_('Personal info'), {
|
||||
'fields': ('firstname', 'lastname', 'date_of_birth', 'female'),
|
||||
'classes': ('wide',) # フィールドの表示を広げる
|
||||
}),
|
||||
(_('Permissions'), {'fields': ('is_staff', 'is_active', 'is_rogaining','user_permissions')}),
|
||||
(_('Rogaining info'), {
|
||||
'fields': ('zekken_number', 'event_code', 'team_name', 'group'),
|
||||
'classes': ('wide',)
|
||||
}),
|
||||
(_('Important dates'), {
|
||||
'fields': ('date_joined','last_login'),
|
||||
'classes': ('wide',)
|
||||
}), # 読み取り専用
|
||||
)
|
||||
add_fieldsets = (
|
||||
(None, {
|
||||
'classes': ('wide',),
|
||||
#'fields': ('email', 'password1', 'password2', 'is_staff', 'is_active', 'is_rogaining')}
|
||||
'fields': ('email', 'password1', 'password2', 'lastname','firstname', 'date_of_birth', 'female','is_staff', 'is_active', 'is_rogaining')}
|
||||
),
|
||||
)
|
||||
search_fields = ('email', 'firstname', 'lastname', 'zekken_number', 'team_name')
|
||||
ordering = ('email',)
|
||||
|
||||
def get_readonly_fields(self, request, obj=None):
|
||||
# スーパーユーザーの場合は読み取り専用フィールドを最小限に
|
||||
if request.user.is_superuser:
|
||||
return self.readonly_fields
|
||||
# 通常のスタッフユーザーの場合は追加の制限を設定可能
|
||||
return self.readonly_fields + ('is_staff', 'is_superuser')
|
||||
|
||||
|
||||
admin.site.register(Useractions)
|
||||
admin.site.register(RogUser, admin.ModelAdmin)
|
||||
@ -220,3 +975,7 @@ admin.site.register(CustomUser, UserAdminConfig)
|
||||
admin.site.register(templocation, TempLocationAdmin)
|
||||
admin.site.register(GoalImages, admin.ModelAdmin)
|
||||
admin.site.register(CheckinImages, admin.ModelAdmin)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -3,12 +3,18 @@ from django.conf import settings
|
||||
from .models import CustomUser
|
||||
from django.contrib.auth.backends import ModelBackend
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.hashers import check_password
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class EmailOrUsernameModelBackend(ModelBackend):
|
||||
"""
|
||||
This is a ModelBacked that allows authentication
|
||||
with either a username or an email address.
|
||||
|
||||
"""
|
||||
"""
|
||||
def authenticate(self, username=None, password=None):
|
||||
if '@' in username:
|
||||
@ -27,3 +33,34 @@ class EmailOrUsernameModelBackend(ModelBackend):
|
||||
return CustomUser.objects.get(pk=username)
|
||||
except get_user_model().DoesNotExist:
|
||||
return None
|
||||
"""
|
||||
|
||||
def authenticate(self, request, username=None, password=None, **kwargs):
|
||||
if '@' in username:
|
||||
kwargs = {'email': username}
|
||||
else:
|
||||
kwargs = {'username': username}
|
||||
try:
|
||||
user = CustomUser.objects.get(**kwargs)
|
||||
if check_password(password, user.password):
|
||||
logger.info(f"User authenticated successfully: {username}")
|
||||
return user
|
||||
else:
|
||||
logger.warning(f"Password mismatch for user: {username}")
|
||||
except CustomUser.DoesNotExist:
|
||||
logger.warning(f"User does not exist: {username}")
|
||||
except Exception as e:
|
||||
logger.error(f"Authentication error for {username}: {str(e)}")
|
||||
return None
|
||||
|
||||
def get_user(self, user_id):
|
||||
try:
|
||||
user = CustomUser.objects.get(pk=user_id)
|
||||
logger.info(f"User retrieved: {user.username or user.email}")
|
||||
return user
|
||||
except CustomUser.DoesNotExist:
|
||||
logger.warning(f"User with id {user_id} does not exist")
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.error(f"Error retrieving user with id {user_id}: {str(e)}")
|
||||
return None
|
||||
|
||||
7
rog/forms.py
Normal file
7
rog/forms.py
Normal file
@ -0,0 +1,7 @@
|
||||
from django import forms
|
||||
from .models import NewEvent2
|
||||
|
||||
class CSVUploadForm(forms.Form):
|
||||
event = forms.ModelChoiceField(queryset=NewEvent2.objects.all(), label="イベント選択")
|
||||
csv_file = forms.FileField(label="CSVファイル")
|
||||
|
||||
40
rog/gifuroge_team.csv
Normal file
40
rog/gifuroge_team.csv
Normal file
@ -0,0 +1,40 @@
|
||||
4019,関ケ原2,Best Wishes,ソロ女子-5時間,pbkdf2_sha256$260000$RPvncicp11ENXxwpcpMXi1$9e/fKcfwaX3sJ91q9S70KWQcrNlraliguiHjF/UCW/I=
|
||||
4010,関ケ原2,まつげん,ソロ女子-5時間,pbkdf2_sha256$260000$LMvH0KtHeHbCuuUZ5n88VZ$Lnsqs/u45QKoFN6lUdqC79nIMz5LwaKWMpmX/0aEXa8=
|
||||
4021,大垣3,まつげん,ソロ女子-5時間,pbkdf2_sha256$260000$LMvH0KtHeHbCuuUZ5n88VZ$Lnsqs/u45QKoFN6lUdqC79nIMz5LwaKWMpmX/0aEXa8=
|
||||
5,関ケ原2,てすとあきら1,ソロ男子-5時間,pbkdf2_sha256$260000$0GY5pt5V127jGd8HkkEort$8ZL0eY2qTZHydyzUUN5LNKZnmmibfu1x3QQ/7rJX1Vc=
|
||||
3003,関ケ原2,てすとあきら1,ソロ男子-5時間,pbkdf2_sha256$260000$0GY5pt5V127jGd8HkkEort$8ZL0eY2qTZHydyzUUN5LNKZnmmibfu1x3QQ/7rJX1Vc=
|
||||
3115,関ケ原2,Best Wishes,ソロ男子-5時間,pbkdf2_sha256$260000$tlNrgHyqDtfbM9f3GLv5G1$jRcR/ieTB174TZ9jW7obCBUMpyz86aywqDKw3VmhVQQ=
|
||||
1010,大垣3,ハヤノテスト,一般-5時間,pbkdf2_sha256$260000$IeGmRkkUkwXXc1zO9oxvCe$ijnJTH7xhwidit+uCggSgjj/7g/vMK539IpOMA5GlnM=
|
||||
1012,大垣3,てすとあきら1,一般-5時間,pbkdf2_sha256$260000$0GY5pt5V127jGd8HkkEort$8ZL0eY2qTZHydyzUUN5LNKZnmmibfu1x3QQ/7rJX1Vc=
|
||||
1014,各務原2,てすとあきら1,一般-5時間,pbkdf2_sha256$260000$0GY5pt5V127jGd8HkkEort$8ZL0eY2qTZHydyzUUN5LNKZnmmibfu1x3QQ/7rJX1Vc=
|
||||
1018,下呂2,てすとあきら1,一般-5時間,pbkdf2_sha256$260000$0GY5pt5V127jGd8HkkEort$8ZL0eY2qTZHydyzUUN5LNKZnmmibfu1x3QQ/7rJX1Vc=
|
||||
1024,関ケ原2,てすとあきら1,一般-5時間,pbkdf2_sha256$260000$0GY5pt5V127jGd8HkkEort$8ZL0eY2qTZHydyzUUN5LNKZnmmibfu1x3QQ/7rJX1Vc=
|
||||
1026,美濃加茂2,てすとあきら1,一般-5時間,pbkdf2_sha256$260000$0GY5pt5V127jGd8HkkEort$8ZL0eY2qTZHydyzUUN5LNKZnmmibfu1x3QQ/7rJX1Vc=
|
||||
1028,多治見2,てすとあきら1,一般-5時間,pbkdf2_sha256$260000$0GY5pt5V127jGd8HkkEort$8ZL0eY2qTZHydyzUUN5LNKZnmmibfu1x3QQ/7rJX1Vc=
|
||||
3006,関ケ原2,山本哲也,ソロ男子-5時間,pbkdf2_sha256$260000$EkYrRHZwKunjO4jiHvxyB2$kYGN0STzV9c70IKAIxK1Ija3K1y90+ote0HDTP+iSPw=
|
||||
3009,養老2,山本哲也,ソロ男子-5時間,pbkdf2_sha256$260000$EkYrRHZwKunjO4jiHvxyB2$kYGN0STzV9c70IKAIxK1Ija3K1y90+ote0HDTP+iSPw=
|
||||
3011,郡上2,山本哲也,ソロ男子-5時間,pbkdf2_sha256$260000$EkYrRHZwKunjO4jiHvxyB2$kYGN0STzV9c70IKAIxK1Ija3K1y90+ote0HDTP+iSPw=
|
||||
3013,大垣3,山本哲也,ソロ男子-5時間,pbkdf2_sha256$260000$EkYrRHZwKunjO4jiHvxyB2$kYGN0STzV9c70IKAIxK1Ija3K1y90+ote0HDTP+iSPw=
|
||||
3015,各務原2,山本哲也,ソロ男子-5時間,pbkdf2_sha256$260000$EkYrRHZwKunjO4jiHvxyB2$kYGN0STzV9c70IKAIxK1Ija3K1y90+ote0HDTP+iSPw=
|
||||
3017,多治見2,山本哲也,ソロ男子-5時間,pbkdf2_sha256$260000$EkYrRHZwKunjO4jiHvxyB2$kYGN0STzV9c70IKAIxK1Ija3K1y90+ote0HDTP+iSPw=
|
||||
3019,下呂2,山本哲也,ソロ男子-5時間,pbkdf2_sha256$260000$EkYrRHZwKunjO4jiHvxyB2$kYGN0STzV9c70IKAIxK1Ija3K1y90+ote0HDTP+iSPw=
|
||||
3021,高山2,山本哲也,ソロ男子-5時間,pbkdf2_sha256$260000$EkYrRHZwKunjO4jiHvxyB2$kYGN0STzV9c70IKAIxK1Ija3K1y90+ote0HDTP+iSPw=
|
||||
3023,美濃加茂2,山本哲也,ソロ男子-5時間,pbkdf2_sha256$260000$EkYrRHZwKunjO4jiHvxyB2$kYGN0STzV9c70IKAIxK1Ija3K1y90+ote0HDTP+iSPw=
|
||||
4008,下呂2,GO!GO!YOKO,ソロ女子-5時間,pbkdf2_sha256$260000$tuv8ajw2VSmCooIxNHJhdD$m7q0fqPIsAs7L9uubt+PUVsmexwpJPXPCgVs9GjY12c=
|
||||
3121,関ケ原2,yamadeus,ソロ男子-5時間,pbkdf2_sha256$260000$sCLRTCAxQIClyDmvfbMDm0$cU3dSGTPwKHl8T3EBZ6R19oZJGkadD48pKqywAhtJOk=
|
||||
3126,大垣3,yamadeus,ソロ男子-5時間,pbkdf2_sha256$260000$7KsSngw2Ho719jpXsOrC8v$jfHFxglG/L0htA13t01LAy91dS+FnlAZubg6Lmd/m2Y=
|
||||
3128,多治見2,MASA,ソロ男子-5時間,pbkdf2_sha256$260000$qpaSbqryD4f5bZaY893Ug4$Gk8XuqsJbSkX9Hxrl/xg9LtjM8JQkpgNkpbbNzTmhzY=
|
||||
3124,関ケ原2,yamadeus,ソロ男子-5時間,pbkdf2_sha256$260000$7KsSngw2Ho719jpXsOrC8v$jfHFxglG/L0htA13t01LAy91dS+FnlAZubg6Lmd/m2Y=
|
||||
3132,各務原2,岐阜市イイとこあるある探検隊,ソロ男子-5時間,pbkdf2_sha256$260000$QWc5BpSBUbkUwP9UlIzyE5$do+VKkH8mNibg6PJDsm6AJ/VMFh3NWdzwZ9IQW/26xA=
|
||||
3135,大垣3,akira,ソロ男子-5時間,pbkdf2_sha256$260000$mmM2N8sSE84YaNNuDzQKxb$ox9U6rdgZq4ANzi4NizskphZWIrf7o2+JEfvC4wcn7U=
|
||||
3137,関ケ原2,akira,ソロ男子-5時間,pbkdf2_sha256$260000$mmM2N8sSE84YaNNuDzQKxb$ox9U6rdgZq4ANzi4NizskphZWIrf7o2+JEfvC4wcn7U=
|
||||
3139,養老2,akira,ソロ男子-5時間,pbkdf2_sha256$260000$mmM2N8sSE84YaNNuDzQKxb$ox9U6rdgZq4ANzi4NizskphZWIrf7o2+JEfvC4wcn7U=
|
||||
3073,養老2,yamadeus,ソロ男子-5時間,pbkdf2_sha256$260000$sCLRTCAxQIClyDmvfbMDm0$cU3dSGTPwKHl8T3EBZ6R19oZJGkadD48pKqywAhtJOk=
|
||||
3075,高山2,yamadeus,ソロ男子-5時間,pbkdf2_sha256$260000$sCLRTCAxQIClyDmvfbMDm0$cU3dSGTPwKHl8T3EBZ6R19oZJGkadD48pKqywAhtJOk=
|
||||
3077,郡上2,yamadeus,ソロ男子-5時間,pbkdf2_sha256$260000$sCLRTCAxQIClyDmvfbMDm0$cU3dSGTPwKHl8T3EBZ6R19oZJGkadD48pKqywAhtJOk=
|
||||
3081,美濃加茂2,yamadeus,ソロ男子-5時間,pbkdf2_sha256$260000$sCLRTCAxQIClyDmvfbMDm0$cU3dSGTPwKHl8T3EBZ6R19oZJGkadD48pKqywAhtJOk=
|
||||
3083,多治見2,yamadeus,ソロ男子-5時間,pbkdf2_sha256$260000$sCLRTCAxQIClyDmvfbMDm0$cU3dSGTPwKHl8T3EBZ6R19oZJGkadD48pKqywAhtJOk=
|
||||
3085,各務原2,yamadeus,ソロ男子-5時間,pbkdf2_sha256$260000$sCLRTCAxQIClyDmvfbMDm0$cU3dSGTPwKHl8T3EBZ6R19oZJGkadD48pKqywAhtJOk=
|
||||
3079,下呂2,yamadeus,ソロ男子-5時間,pbkdf2_sha256$260000$sCLRTCAxQIClyDmvfbMDm0$cU3dSGTPwKHl8T3EBZ6R19oZJGkadD48pKqywAhtJOk=
|
||||
3093,関ケ原2,岐阜愛,ソロ男子-5時間,pbkdf2_sha256$260000$LFOINdd30aKaXoT9CNYY8A$eoAzV10+gp+tufabtcFOx6uoOktZUngzzDJ0WWs/v24=
|
||||
3099,高山2,岐阜愛,ソロ男子-5時間,pbkdf2_sha256$260000$LFOINdd30aKaXoT9CNYY8A$eoAzV10+gp+tufabtcFOx6uoOktZUngzzDJ0WWs/v24=
|
||||
|
3
rog/middleware/__init__.py
Normal file
3
rog/middleware/__init__.py
Normal file
@ -0,0 +1,3 @@
|
||||
from .ip_blocking import IPBlockingMiddleware
|
||||
|
||||
__all__ = ['IPBlockingMiddleware']
|
||||
42
rog/middleware/ip_blocking.py
Normal file
42
rog/middleware/ip_blocking.py
Normal file
@ -0,0 +1,42 @@
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.core.cache import cache
|
||||
from django.conf import settings
|
||||
|
||||
class IPBlockingMiddleware:
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
# 事前にブロックする IP アドレスのリスト
|
||||
self.blacklisted_ips = getattr(settings, 'BLACKLISTED_IPS', [])
|
||||
|
||||
def __call__(self, request):
|
||||
ip = self.get_client_ip(request)
|
||||
|
||||
# キャッシュからブロックリストを取得
|
||||
blocked_ips = cache.get('blocked_ips', set())
|
||||
|
||||
# 事前にブロックされた IP またはキャッシュ内のブロックされた IP をチェック
|
||||
if ip in self.blacklisted_ips or ip in blocked_ips:
|
||||
raise PermissionDenied
|
||||
|
||||
# 不正アクセスの検出ロジックをここに実装
|
||||
if self.is_suspicious(ip):
|
||||
blocked_ips.add(ip)
|
||||
cache.set('blocked_ips', blocked_ips, timeout=3600) # 1時間ブロック
|
||||
raise PermissionDenied
|
||||
|
||||
response = self.get_response(request)
|
||||
return response
|
||||
|
||||
def is_suspicious(self, ip):
|
||||
request_count = cache.get(f'request_count_{ip}', 0)
|
||||
cache.set(f'request_count_{ip}', request_count + 1, timeout=60)
|
||||
return request_count > 100 # 1分間に100回以上のリクエストがあれば不審と判断
|
||||
|
||||
def get_client_ip(self, request):
|
||||
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||
if x_forwarded_for:
|
||||
ip = x_forwarded_for.split(',')[0]
|
||||
else:
|
||||
ip = request.META.get('REMOTE_ADDR')
|
||||
return ip
|
||||
|
||||
148
rog/migration_scripts.py
Normal file
148
rog/migration_scripts.py
Normal file
@ -0,0 +1,148 @@
|
||||
"""
|
||||
このコードは永栄コードをNoufferコードに統合するための一時変換コードです。
|
||||
一旦、完全にマイグレーションでき、ランキングや走行履歴が完成したら、不要になります。
|
||||
"""
|
||||
import psycopg2
|
||||
from PIL import Image
|
||||
import PIL.ExifTags
|
||||
from datetime import datetime
|
||||
import os
|
||||
|
||||
def get_gps_from_image(image_path):
|
||||
"""
|
||||
画像ファイルからGPS情報を抽出する
|
||||
Returns: (latitude, longitude) または取得できない場合は (None, None)
|
||||
"""
|
||||
try:
|
||||
with Image.open(image_path) as img:
|
||||
exif = {
|
||||
PIL.ExifTags.TAGS[k]: v
|
||||
for k, v in img._getexif().items()
|
||||
if k in PIL.ExifTags.TAGS
|
||||
}
|
||||
|
||||
if 'GPSInfo' in exif:
|
||||
gps_info = exif['GPSInfo']
|
||||
|
||||
# 緯度の計算
|
||||
lat = gps_info[2]
|
||||
lat = lat[0] + lat[1]/60 + lat[2]/3600
|
||||
if gps_info[1] == 'S':
|
||||
lat = -lat
|
||||
|
||||
# 経度の計算
|
||||
lon = gps_info[4]
|
||||
lon = lon[0] + lon[1]/60 + lon[2]/3600
|
||||
if gps_info[3] == 'W':
|
||||
lon = -lon
|
||||
|
||||
return lat, lon
|
||||
except Exception as e:
|
||||
print(f"GPS情報の抽出に失敗: {e}")
|
||||
|
||||
return None, None
|
||||
|
||||
def migrate_data():
|
||||
# コンテナ環境用の接続情報
|
||||
source_db = {
|
||||
'dbname': 'gifuroge',
|
||||
'user': 'admin', # 環境に合わせて変更
|
||||
'password': 'admin123456', # 環境に合わせて変更
|
||||
'host': 'localhost', # Dockerのサービス名
|
||||
'port': '5432'
|
||||
}
|
||||
|
||||
target_db = {
|
||||
'dbname': 'rogdb',
|
||||
'user': 'admin', # 環境に合わせて変更
|
||||
'password': 'admin123456', # 環境に合わせて変更
|
||||
'host': 'localhost', # Dockerのサービス名
|
||||
'port': '5432'
|
||||
}
|
||||
|
||||
source_conn = None
|
||||
target_conn = None
|
||||
source_cur = None
|
||||
target_cur = None
|
||||
|
||||
try:
|
||||
print("ソースDBへの接続を試みています...")
|
||||
source_conn = psycopg2.connect(**source_db)
|
||||
source_cur = source_conn.cursor()
|
||||
print("ソースDBへの接続が成功しました")
|
||||
|
||||
print("ターゲットDBへの接続を試みています...")
|
||||
target_conn = psycopg2.connect(**target_db)
|
||||
target_cur = target_conn.cursor()
|
||||
print("ターゲットDBへの接続が成功しました")
|
||||
|
||||
print("データの取得を開始します...")
|
||||
source_cur.execute("""
|
||||
SELECT serial_number, zekken_number, event_code, cp_number, image_address,
|
||||
goal_time, late_point, create_at, create_user,
|
||||
update_at, update_user, buy_flag, colabo_company_memo
|
||||
FROM gps_information
|
||||
""")
|
||||
|
||||
rows = source_cur.fetchall()
|
||||
print(f"取得したレコード数: {len(rows)}")
|
||||
|
||||
processed_count = 0
|
||||
for row in rows:
|
||||
(serial_number, zekken_number, event_code, cp_number, image_address,
|
||||
goal_time, late_point, create_at, create_user,
|
||||
update_at, update_user, buy_flag, colabo_company_memo) = row
|
||||
|
||||
latitude, longitude = None, None
|
||||
if image_address and os.path.exists(image_address):
|
||||
latitude, longitude = get_gps_from_image(image_address)
|
||||
|
||||
target_cur.execute("""
|
||||
INSERT INTO gps_checkins (
|
||||
path_order, zekken_number, event_code, cp_number,
|
||||
lattitude, longitude, image_address,
|
||||
image_receipt, image_QR, validate_location,
|
||||
goal_time, late_point, create_at,
|
||||
create_user, update_at, update_user,
|
||||
buy_flag, colabo_company_memo, points
|
||||
) VALUES (
|
||||
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
|
||||
%s, %s, %s, %s, %s, %s, %s, %s, %s
|
||||
)
|
||||
""", (
|
||||
serial_number,
|
||||
zekken_number, event_code, cp_number,
|
||||
latitude, longitude, image_address,
|
||||
True, True, True,
|
||||
goal_time, late_point, create_at,
|
||||
create_user, update_at, update_user,
|
||||
buy_flag if buy_flag is not None else False,
|
||||
colabo_company_memo if colabo_company_memo else '',
|
||||
0
|
||||
))
|
||||
|
||||
processed_count += 1
|
||||
if processed_count % 100 == 0:
|
||||
print(f"処理済みレコード数: {processed_count}")
|
||||
|
||||
target_conn.commit()
|
||||
print(f"移行完了: {processed_count}件のレコードを処理しました")
|
||||
|
||||
except Exception as e:
|
||||
print(f"エラーが発生しました: {e}")
|
||||
if target_conn:
|
||||
target_conn.rollback()
|
||||
|
||||
finally:
|
||||
if source_cur:
|
||||
source_cur.close()
|
||||
if target_cur:
|
||||
target_cur.close()
|
||||
if source_conn:
|
||||
source_conn.close()
|
||||
if target_conn:
|
||||
target_conn.close()
|
||||
print("すべての接続をクローズしました")
|
||||
|
||||
if __name__ == "__main__":
|
||||
migrate_data()
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
351
rog/migrations_backup/0001_initial.py
Normal file
351
rog/migrations_backup/0001_initial.py
Normal file
@ -0,0 +1,351 @@
|
||||
# Generated by Django 3.2.9 on 2022-05-04 15:05
|
||||
|
||||
from django.conf import settings
|
||||
import django.contrib.gis.db.models.fields
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import rog.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('auth', '0012_alter_user_first_name_max_length'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='JpnAdminMainPerf',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('geom', django.contrib.gis.db.models.fields.MultiPolygonField(blank=True, null=True, srid=4326)),
|
||||
('adm0_en', models.CharField(blank=True, max_length=254, null=True)),
|
||||
('adm0_ja', models.CharField(blank=True, max_length=254, null=True)),
|
||||
('adm0_pcode', models.CharField(blank=True, max_length=254, null=True)),
|
||||
('adm1_en', models.CharField(blank=True, max_length=254, null=True)),
|
||||
('adm1_ja', models.CharField(blank=True, max_length=254, null=True)),
|
||||
('adm1_pcode', models.CharField(blank=True, max_length=254, null=True)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'jpn_admin_main_perf',
|
||||
'managed': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='JpnAdminPerf',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('geom', django.contrib.gis.db.models.fields.MultiLineStringField(blank=True, null=True, srid=4326)),
|
||||
('et_id', models.IntegerField(blank=True, null=True)),
|
||||
('et_right', models.CharField(blank=True, max_length=80, null=True)),
|
||||
('et_left', models.CharField(blank=True, max_length=80, null=True)),
|
||||
('adm2_l', models.CharField(blank=True, max_length=50, null=True)),
|
||||
('adm1_l', models.CharField(blank=True, max_length=50, null=True)),
|
||||
('adm0_l', models.CharField(blank=True, max_length=50, null=True)),
|
||||
('adm0_r', models.CharField(blank=True, max_length=50, null=True)),
|
||||
('adm1_r', models.CharField(blank=True, max_length=50, null=True)),
|
||||
('adm2_r', models.CharField(blank=True, max_length=50, null=True)),
|
||||
('admlevel', models.IntegerField(blank=True, null=True)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'jpn_admin_perf',
|
||||
'managed': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='JpnSubPerf',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('geom', django.contrib.gis.db.models.fields.MultiPolygonField(blank=True, null=True, srid=4326)),
|
||||
('adm0_en', models.CharField(blank=True, max_length=254, null=True)),
|
||||
('adm0_ja', models.CharField(blank=True, max_length=254, null=True)),
|
||||
('adm0_pcode', models.CharField(blank=True, max_length=254, null=True)),
|
||||
('adm1_en', models.CharField(blank=True, max_length=254, null=True)),
|
||||
('adm1_ja', models.CharField(blank=True, max_length=254, null=True)),
|
||||
('adm1_pcode', models.CharField(blank=True, max_length=254, null=True)),
|
||||
('adm2_ja', models.CharField(blank=True, max_length=254, null=True)),
|
||||
('adm2_en', models.CharField(blank=True, max_length=254, null=True)),
|
||||
('adm2_pcode', models.CharField(blank=True, max_length=254, null=True)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'jpn_sub_perf',
|
||||
'managed': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='CustomUser',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||
('email', models.EmailField(max_length=254, unique=True, verbose_name='email address')),
|
||||
('is_staff', models.BooleanField(default=False)),
|
||||
('is_active', models.BooleanField(default=False)),
|
||||
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
|
||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Location',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('location_id', models.IntegerField(blank=True, null=True, verbose_name='Location id')),
|
||||
('location_name', models.CharField(default='--- 場所をお願いします --', max_length=255, verbose_name='Location Name')),
|
||||
('category', models.CharField(blank=True, max_length=255, null=True, verbose_name='Category')),
|
||||
('zip', models.CharField(blank=True, max_length=12, null=True, verbose_name='Zip code')),
|
||||
('address', models.CharField(blank=True, max_length=512, null=True, verbose_name='Address')),
|
||||
('prefecture', models.CharField(blank=True, max_length=255, null=True, verbose_name='Prefecture')),
|
||||
('area', models.CharField(blank=True, max_length=255, null=True, verbose_name='Area')),
|
||||
('city', models.CharField(blank=True, max_length=255, null=True, verbose_name='City')),
|
||||
('latitude', models.FloatField(blank=True, null=True, verbose_name='Latitude')),
|
||||
('longitude', models.FloatField(blank=True, null=True, verbose_name='Latitude')),
|
||||
('photos', models.CharField(blank=True, max_length=255, null=True, verbose_name='Phptos')),
|
||||
('videos', models.CharField(blank=True, max_length=255, null=True, verbose_name='Videos')),
|
||||
('webcontents', models.CharField(blank=True, max_length=255, null=True, verbose_name='Web Content')),
|
||||
('status', models.CharField(blank=True, max_length=255, null=True, verbose_name='Status')),
|
||||
('portal', models.CharField(blank=True, max_length=255, null=True, verbose_name='Portal')),
|
||||
('group', models.CharField(blank=True, max_length=255, null=True, verbose_name='Group')),
|
||||
('phone', models.CharField(blank=True, max_length=255, null=True, verbose_name='Phone')),
|
||||
('fax', models.CharField(blank=True, max_length=255, null=True, verbose_name='Fax')),
|
||||
('email', models.EmailField(blank=True, max_length=255, null=True, verbose_name='Email')),
|
||||
('facility', models.CharField(blank=True, max_length=255, null=True, verbose_name='Facility')),
|
||||
('remark', models.CharField(blank=True, max_length=255, null=True, verbose_name='Remarks')),
|
||||
('tags', models.CharField(blank=True, max_length=512, null=True, verbose_name='Tags')),
|
||||
('parammeters', models.CharField(blank=True, max_length=512, null=True, verbose_name='Parameters')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('last_updated_at', models.DateTimeField(auto_now=True)),
|
||||
('geom', django.contrib.gis.db.models.fields.MultiPointField(srid=4326)),
|
||||
('last_updated_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='location_updated_user', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ShapeLayers',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255, verbose_name='Shape Layer')),
|
||||
('file', models.FileField(blank=True, upload_to=rog.models.get_file_path)),
|
||||
('uploaded_date', models.DateField(auto_now_add=True)),
|
||||
('layerof', models.IntegerField(choices=[(1, 'location'), (2, 'Location_line'), (3, 'Location_polygon')], default=1)),
|
||||
('table_name', models.CharField(blank=True, max_length=255, verbose_name='Table name')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TestModel',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('testbane', models.CharField(max_length=355, verbose_name='test field')),
|
||||
('wanttogo', models.BooleanField(default=False)),
|
||||
('like', models.BooleanField(default=False)),
|
||||
('checkin', models.BooleanField(default=False)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('last_updated_at', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TravelList',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('travel_id', models.IntegerField(verbose_name='Travel Id')),
|
||||
('start_date', models.DateTimeField(blank=True, null=True, verbose_name='Start date')),
|
||||
('finish_date', models.DateTimeField(blank=True, null=True, verbose_name='End date')),
|
||||
('category', models.CharField(choices=[('PRIVATE', 'Private'), ('GROUP', 'Group'), ('AGENT', 'Agent'), ('ROGAINING', 'Rogaining')], max_length=256)),
|
||||
('title', models.CharField(max_length=255, verbose_name='Title')),
|
||||
('transportation', models.CharField(blank=True, max_length=255, null=True, verbose_name='Transpotation')),
|
||||
('moving_distance', models.IntegerField(blank=True, null=True)),
|
||||
('duration', models.DurationField(blank=True, null=True, verbose_name='Duration')),
|
||||
('eta', models.DateTimeField(blank=True, null=True)),
|
||||
('parammeters', models.CharField(blank=True, max_length=512, null=True, verbose_name='Parameters')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('last_updated_at', models.DateTimeField(auto_now=True)),
|
||||
('last_updated_user', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='travel_list_updated_user', to=settings.AUTH_USER_MODEL)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Useractions',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('wanttogo', models.BooleanField(default=False)),
|
||||
('like', models.BooleanField(default=False)),
|
||||
('checkin', models.BooleanField(default=False)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('last_updated_at', models.DateTimeField(auto_now=True)),
|
||||
('location', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='action_location', to='rog.location')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='action_user', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TravelPoint',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('distance', models.FloatField(blank=True, null=True)),
|
||||
('transportation', models.CharField(blank=True, max_length=255, null=True, verbose_name='Transpotation')),
|
||||
('eta', models.DateTimeField(blank=True, null=True)),
|
||||
('order_number', models.IntegerField(blank=True, null=True)),
|
||||
('parammeters', models.CharField(blank=True, max_length=512, null=True, verbose_name='Parameters')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('last_updated_at', models.DateTimeField(auto_now=True)),
|
||||
('last_updated_user', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='travelpoint_updated_user', to=settings.AUTH_USER_MODEL)),
|
||||
('location', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rog.location')),
|
||||
('travel_list', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='rog.travellist')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SystemSettings',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('setting_name', models.CharField(max_length=255, verbose_name='Settings Name')),
|
||||
('version', models.CharField(blank=True, max_length=10, null=True, verbose_name='Version')),
|
||||
('effective_date', models.DateTimeField()),
|
||||
('end_date', models.DateTimeField()),
|
||||
('parammeters', models.CharField(max_length=512, verbose_name='Parameters')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('last_updated_at', models.DateTimeField(auto_now=True)),
|
||||
('last_updated_user', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='system_setting_updated_user', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='RogUser',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('email', models.EmailField(max_length=254, verbose_name='Email')),
|
||||
('phone', models.CharField(max_length=55, verbose_name='Phone Number')),
|
||||
('first_name', models.CharField(max_length=255, verbose_name='First Name')),
|
||||
('middle_name', models.CharField(blank=True, max_length=255, null=True, verbose_name='Middle Name')),
|
||||
('last_name', models.CharField(max_length=255, verbose_name='last_name')),
|
||||
('nickname', models.CharField(blank=True, max_length=255, null=True, verbose_name='Nickname')),
|
||||
('country', models.CharField(default='Japan', max_length=255, verbose_name='Country')),
|
||||
('language', models.CharField(default='Japanese', max_length=255, verbose_name='Language')),
|
||||
('prefecture', models.CharField(blank=True, max_length=255, null=True, verbose_name='Prefecture')),
|
||||
('sex', models.CharField(blank=True, default='unknown', max_length=255, null=True, verbose_name='Sex')),
|
||||
('birthyear', models.IntegerField(blank=True, null=True, verbose_name='Birth year')),
|
||||
('family_structure', models.IntegerField(blank=True, null=True, verbose_name='Family Structure')),
|
||||
('level', models.IntegerField(blank=True, default=0, null=True, verbose_name='Level')),
|
||||
('parammeters', models.CharField(max_length=512, verbose_name='Parameters')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('last_updated_at', models.DateTimeField(auto_now=True)),
|
||||
('introducer', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='introduced_uesr', to=settings.AUTH_USER_MODEL)),
|
||||
('last_updated_user', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='roguser_updated_user', to=settings.AUTH_USER_MODEL)),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Location_polygon',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('location_id', models.IntegerField(blank=True, null=True, verbose_name='Location id')),
|
||||
('location_name', models.CharField(max_length=255, verbose_name='Location Name')),
|
||||
('category', models.CharField(blank=True, max_length=255, null=True, verbose_name='Category')),
|
||||
('zip', models.CharField(blank=True, max_length=12, null=True, verbose_name='Zip code')),
|
||||
('address', models.CharField(blank=True, max_length=512, null=True, verbose_name='Address')),
|
||||
('prefecture', models.CharField(blank=True, max_length=255, null=True, verbose_name='Prefecture')),
|
||||
('area', models.CharField(blank=True, max_length=255, null=True, verbose_name='Area')),
|
||||
('city', models.CharField(blank=True, max_length=255, null=True, verbose_name='City')),
|
||||
('photos', models.CharField(blank=True, max_length=255, null=True, verbose_name='Phptos')),
|
||||
('videos', models.CharField(blank=True, max_length=255, null=True, verbose_name='Videos')),
|
||||
('webcontents', models.CharField(blank=True, max_length=255, null=True, verbose_name='Web Content')),
|
||||
('status', models.CharField(blank=True, max_length=255, null=True, verbose_name='Status')),
|
||||
('portal', models.CharField(blank=True, max_length=255, null=True, verbose_name='Portal')),
|
||||
('group', models.CharField(blank=True, max_length=255, null=True, verbose_name='Group')),
|
||||
('phone', models.CharField(blank=True, max_length=255, null=True, verbose_name='Phone')),
|
||||
('fax', models.CharField(blank=True, max_length=255, null=True, verbose_name='Fax')),
|
||||
('email', models.EmailField(blank=True, max_length=255, null=True, verbose_name='Email')),
|
||||
('facility', models.CharField(blank=True, max_length=255, null=True, verbose_name='Facility')),
|
||||
('remark', models.CharField(blank=True, max_length=255, null=True, verbose_name='Remarks')),
|
||||
('tags', models.CharField(blank=True, max_length=512, null=True, verbose_name='Tags')),
|
||||
('parammeters', models.CharField(blank=True, max_length=512, null=True, verbose_name='Parameters')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('last_updated_at', models.DateTimeField(auto_now=True)),
|
||||
('geom', django.contrib.gis.db.models.fields.MultiPolygonField(blank=True, null=True, srid=4326)),
|
||||
('last_updated_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='location_polygon_updated_user', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Location_line',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('location_id', models.IntegerField(blank=True, null=True, verbose_name='Location id')),
|
||||
('location_name', models.CharField(max_length=255, verbose_name='Location Name')),
|
||||
('category', models.CharField(blank=True, max_length=255, null=True, verbose_name='Category')),
|
||||
('zip', models.CharField(blank=True, max_length=12, null=True, verbose_name='Zip code')),
|
||||
('address', models.CharField(blank=True, max_length=512, null=True, verbose_name='Address')),
|
||||
('prefecture', models.CharField(blank=True, max_length=255, null=True, verbose_name='Prefecture')),
|
||||
('area', models.CharField(blank=True, max_length=255, null=True, verbose_name='Area')),
|
||||
('city', models.CharField(blank=True, max_length=255, null=True, verbose_name='City')),
|
||||
('photos', models.CharField(blank=True, max_length=255, null=True, verbose_name='Phptos')),
|
||||
('videos', models.CharField(blank=True, max_length=255, null=True, verbose_name='Videos')),
|
||||
('webcontents', models.CharField(blank=True, max_length=255, null=True, verbose_name='Web Content')),
|
||||
('status', models.CharField(blank=True, max_length=255, null=True, verbose_name='Status')),
|
||||
('portal', models.CharField(blank=True, max_length=255, null=True, verbose_name='Portal')),
|
||||
('group', models.CharField(blank=True, max_length=255, null=True, verbose_name='Group')),
|
||||
('phone', models.CharField(blank=True, max_length=255, null=True, verbose_name='Phone')),
|
||||
('fax', models.CharField(blank=True, max_length=255, null=True, verbose_name='Fax')),
|
||||
('email', models.EmailField(blank=True, max_length=255, null=True, verbose_name='Email')),
|
||||
('facility', models.CharField(blank=True, max_length=255, null=True, verbose_name='Facility')),
|
||||
('remark', models.CharField(blank=True, max_length=255, null=True, verbose_name='Remarks')),
|
||||
('tags', models.CharField(blank=True, max_length=512, null=True, verbose_name='Tags')),
|
||||
('parammeters', models.CharField(blank=True, max_length=512, null=True, verbose_name='Parameters')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('last_updated_at', models.DateTimeField(auto_now=True)),
|
||||
('geom', django.contrib.gis.db.models.fields.MultiLineStringField(blank=True, null=True, srid=4326)),
|
||||
('last_updated_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='location_line_updated_user', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='JoinedEvent',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('tagname', models.CharField(blank=True, max_length=255, null=True, verbose_name='Tag Name')),
|
||||
('status', models.CharField(choices=[('REGISTERED', 'Registered'), ('ACCEPTED', 'accepted'), ('PAID', 'paid'), ('JOINED', 'joined'), ('CANCELED', 'Canceled')], max_length=256)),
|
||||
('registrationid', models.CharField(max_length=56, verbose_name='Registration Id')),
|
||||
('payment_code', models.CharField(max_length=255, verbose_name='Payment Code')),
|
||||
('paid', models.IntegerField(default=0, verbose_name='Paid Amount')),
|
||||
('remark', models.CharField(blank=True, max_length=255, null=True, verbose_name='Remark')),
|
||||
('parammeters', models.CharField(max_length=512, verbose_name='Parameters')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('last_updated_at', models.DateTimeField(auto_now=True)),
|
||||
('last_updated_user', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='joined_event_updated_user', to=settings.AUTH_USER_MODEL)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Favorite',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('good', models.IntegerField(default=0, verbose_name='Good')),
|
||||
('favorite', models.IntegerField(default=0, verbose_name='Favorite')),
|
||||
('evaluation', models.IntegerField(default=0, verbose_name='Evaluation')),
|
||||
('number_visit', models.IntegerField(default=0, verbose_name='Good')),
|
||||
('last_visited', models.DateTimeField(blank=True, null=True, verbose_name='Last Visited')),
|
||||
('parammeters', models.CharField(blank=True, max_length=512, null=True, verbose_name='Parameters')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('last_updated_at', models.DateTimeField(auto_now=True)),
|
||||
('last_updated_user', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='favorite_updated_user', to=settings.AUTH_USER_MODEL)),
|
||||
('location', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rog.location')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Event',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('tagname', models.CharField(blank=True, max_length=512, null=True, verbose_name='Parameters')),
|
||||
('status', models.CharField(choices=[('PREPARING', 'Preparing'), ('PROMOTION', 'Promotion'), ('EVENT', 'Event'), ('END', 'End')], max_length=256)),
|
||||
('price', models.IntegerField(default=0, verbose_name='Paid Amount')),
|
||||
('promotion_date', models.DateTimeField(blank=True, null=True, verbose_name='Promotion date')),
|
||||
('event_start', models.DateTimeField(blank=True, null=True, verbose_name='Promotion date')),
|
||||
('event_end', models.DateTimeField(blank=True, null=True, verbose_name='Promotion date')),
|
||||
('remark', models.CharField(blank=True, max_length=256, null=True)),
|
||||
('parammeters', models.CharField(blank=True, max_length=512, null=True, verbose_name='Parameters')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('last_updated_at', models.DateTimeField(auto_now=True)),
|
||||
('last_updated_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='event_updated_user', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
23
rog/migrations_backup/0002_auto_20220511_2017.py
Normal file
23
rog/migrations_backup/0002_auto_20220511_2017.py
Normal file
@ -0,0 +1,23 @@
|
||||
# Generated by Django 3.2.9 on 2022-05-11 11:17
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='useractions',
|
||||
name='order',
|
||||
field=models.IntegerField(default=-1),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='customuser',
|
||||
name='is_active',
|
||||
field=models.BooleanField(default=True),
|
||||
),
|
||||
]
|
||||
18
rog/migrations_backup/0003_alter_useractions_order.py
Normal file
18
rog/migrations_backup/0003_alter_useractions_order.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2.9 on 2022-05-11 17:52
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0002_auto_20220511_2017'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='useractions',
|
||||
name='order',
|
||||
field=models.IntegerField(default=0),
|
||||
),
|
||||
]
|
||||
55
rog/migrations_backup/0004_auto_20220606_0023.py
Normal file
55
rog/migrations_backup/0004_auto_20220606_0023.py
Normal file
@ -0,0 +1,55 @@
|
||||
# Generated by Django 3.2.9 on 2022-06-05 15:23
|
||||
|
||||
import django.contrib.gis.db.models.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0003_alter_useractions_order'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='GifuAreas',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('geom', django.contrib.gis.db.models.fields.MultiPolygonField(blank=True, null=True, srid=4326)),
|
||||
('adm0_en', models.CharField(blank=True, max_length=254, null=True)),
|
||||
('adm0_ja', models.CharField(blank=True, max_length=254, null=True)),
|
||||
('adm0_pcode', models.CharField(blank=True, max_length=254, null=True)),
|
||||
('adm1_en', models.CharField(blank=True, max_length=254, null=True)),
|
||||
('adm1_ja', models.CharField(blank=True, max_length=254, null=True)),
|
||||
('adm1_pcode', models.CharField(blank=True, max_length=254, null=True)),
|
||||
('adm2_ja', models.CharField(blank=True, max_length=254, null=True)),
|
||||
('adm2_en', models.CharField(blank=True, max_length=254, null=True)),
|
||||
('adm2_pcode', models.CharField(blank=True, max_length=254, null=True)),
|
||||
('area_nm', models.CharField(blank=True, max_length=254, null=True)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'gifu_areas',
|
||||
'managed': False,
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='auto_checkin',
|
||||
field=models.BooleanField(default=False, verbose_name='Is Autologin'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='checkin_radious',
|
||||
field=models.IntegerField(blank=True, null=True, verbose_name='Checkin Radious'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='event_active',
|
||||
field=models.BooleanField(default=True, verbose_name='Is Autologin'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='event_name',
|
||||
field=models.CharField(blank=True, max_length=512, null=True, verbose_name='Tags'),
|
||||
),
|
||||
]
|
||||
23
rog/migrations_backup/0005_auto_20220606_1523.py
Normal file
23
rog/migrations_backup/0005_auto_20220606_1523.py
Normal file
@ -0,0 +1,23 @@
|
||||
# Generated by Django 3.2.9 on 2022-06-06 06:23
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0004_auto_20220606_0023'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='event_active',
|
||||
field=models.BooleanField(default=True, verbose_name='Is Event active'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='event_name',
|
||||
field=models.CharField(blank=True, max_length=512, null=True, verbose_name='Event name'),
|
||||
),
|
||||
]
|
||||
18
rog/migrations_backup/0006_location_paid.py
Normal file
18
rog/migrations_backup/0006_location_paid.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2.9 on 2022-06-07 13:00
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0005_auto_20220606_1523'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='paid',
|
||||
field=models.BooleanField(default=False, verbose_name='Is Paid'),
|
||||
),
|
||||
]
|
||||
22
rog/migrations_backup/0007_auto_20220607_2207.py
Normal file
22
rog/migrations_backup/0007_auto_20220607_2207.py
Normal file
@ -0,0 +1,22 @@
|
||||
# Generated by Django 3.2.9 on 2022-06-07 13:07
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0006_location_paid'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='location',
|
||||
name='paid',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='roguser',
|
||||
name='paid',
|
||||
field=models.BooleanField(default=False, verbose_name='Is Paid'),
|
||||
),
|
||||
]
|
||||
18
rog/migrations_backup/0008_alter_roguser_parammeters.py
Normal file
18
rog/migrations_backup/0008_alter_roguser_parammeters.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2.9 on 2022-06-07 13:09
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0007_auto_20220607_2207'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='roguser',
|
||||
name='parammeters',
|
||||
field=models.CharField(blank=True, max_length=512, null=True, verbose_name='Parameters'),
|
||||
),
|
||||
]
|
||||
17
rog/migrations_backup/0009_remove_roguser_email.py
Normal file
17
rog/migrations_backup/0009_remove_roguser_email.py
Normal file
@ -0,0 +1,17 @@
|
||||
# Generated by Django 3.2.9 on 2022-06-07 14:24
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0008_alter_roguser_parammeters'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='roguser',
|
||||
name='email',
|
||||
),
|
||||
]
|
||||
18
rog/migrations_backup/0010_useractions_checkinimage.py
Normal file
18
rog/migrations_backup/0010_useractions_checkinimage.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2.9 on 2022-06-10 06:25
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0009_remove_roguser_email'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='useractions',
|
||||
name='checkinimage',
|
||||
field=models.FileField(blank=True, null=True, upload_to='%y%m%d'),
|
||||
),
|
||||
]
|
||||
25
rog/migrations_backup/0011_usertracks.py
Normal file
25
rog/migrations_backup/0011_usertracks.py
Normal file
@ -0,0 +1,25 @@
|
||||
# Generated by Django 3.2.9 on 2022-06-12 18:11
|
||||
|
||||
from django.conf import settings
|
||||
import django.contrib.gis.db.models.fields
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0010_useractions_checkinimage'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='UserTracks',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('geom', django.contrib.gis.db.models.fields.MultiPointField(srid=4326)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
113
rog/migrations_backup/0012_auto_20220613_1758.py
Normal file
113
rog/migrations_backup/0012_auto_20220613_1758.py
Normal file
@ -0,0 +1,113 @@
|
||||
# Generated by Django 3.2.9 on 2022-06-13 08:58
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0011_usertracks'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='address',
|
||||
field=models.CharField(blank=True, max_length=2048, null=True, verbose_name='Address'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='area',
|
||||
field=models.CharField(blank=True, max_length=2048, null=True, verbose_name='Area'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='category',
|
||||
field=models.CharField(blank=True, max_length=2048, null=True, verbose_name='Category'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='city',
|
||||
field=models.CharField(blank=True, max_length=2048, null=True, verbose_name='City'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='email',
|
||||
field=models.EmailField(blank=True, max_length=2048, null=True, verbose_name='Email'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='event_name',
|
||||
field=models.CharField(blank=True, max_length=2048, null=True, verbose_name='Event name'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='facility',
|
||||
field=models.CharField(blank=True, max_length=2048, null=True, verbose_name='Facility'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='fax',
|
||||
field=models.CharField(blank=True, max_length=2048, null=True, verbose_name='Fax'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='group',
|
||||
field=models.CharField(blank=True, max_length=2048, null=True, verbose_name='Group'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='location_name',
|
||||
field=models.CharField(default='--- 場所をお願いします --', max_length=2048, verbose_name='Location Name'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='parammeters',
|
||||
field=models.CharField(blank=True, max_length=2048, null=True, verbose_name='Parameters'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='phone',
|
||||
field=models.CharField(blank=True, max_length=2048, null=True, verbose_name='Phone'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='photos',
|
||||
field=models.CharField(blank=True, max_length=2048, null=True, verbose_name='Phptos'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='portal',
|
||||
field=models.CharField(blank=True, max_length=2048, null=True, verbose_name='Portal'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='prefecture',
|
||||
field=models.CharField(blank=True, max_length=2048, null=True, verbose_name='Prefecture'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='remark',
|
||||
field=models.CharField(blank=True, max_length=2048, null=True, verbose_name='Remarks'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='status',
|
||||
field=models.CharField(blank=True, max_length=2048, null=True, verbose_name='Status'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='tags',
|
||||
field=models.CharField(blank=True, max_length=2048, null=True, verbose_name='Tags'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='videos',
|
||||
field=models.CharField(blank=True, max_length=2048, null=True, verbose_name='Videos'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='webcontents',
|
||||
field=models.CharField(blank=True, max_length=2048, null=True, verbose_name='Web Content'),
|
||||
),
|
||||
]
|
||||
88
rog/migrations_backup/0013_auto_20220618_1847.py
Normal file
88
rog/migrations_backup/0013_auto_20220618_1847.py
Normal file
@ -0,0 +1,88 @@
|
||||
# Generated by Django 3.2.9 on 2022-06-18 09:47
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0012_auto_20220613_1758'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='buy_point',
|
||||
field=models.IntegerField(blank=True, default=0, null=True, verbose_name='buy Point'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='checkin_point',
|
||||
field=models.IntegerField(blank=True, default=10, null=True, verbose_name='Checkin Point'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='checkin_radius',
|
||||
field=models.IntegerField(blank=True, default=15, null=True, verbose_name='Checkin radious'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='evaluation_value',
|
||||
field=models.CharField(blank=True, max_length=2048, null=True, verbose_name='Evaluation value (評価)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='hidden_location',
|
||||
field=models.BooleanField(default=False, verbose_name='Is Hidden Location'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='opening_hours_fri',
|
||||
field=models.TimeField(blank=True, null=True, verbose_name='Opening hours frinday (金曜)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='opening_hours_mon',
|
||||
field=models.TimeField(blank=True, null=True, verbose_name='Opening hours monday (月曜)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='opening_hours_sat',
|
||||
field=models.TimeField(blank=True, null=True, verbose_name='Opening hours saturday (土曜)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='opening_hours_sun',
|
||||
field=models.TimeField(blank=True, null=True, verbose_name='Opening hours sunday (日曜)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='opening_hours_thu',
|
||||
field=models.TimeField(blank=True, null=True, verbose_name='Opening hours thursday (木曜)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='opening_hours_tue',
|
||||
field=models.TimeField(blank=True, null=True, verbose_name='Opening hours tuesday (火曜)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='opening_hours_wed',
|
||||
field=models.TimeField(blank=True, null=True, verbose_name='Opening hours wednesday (水曜)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='shop_closed',
|
||||
field=models.BooleanField(default=False, verbose_name='Shop Closed (休業)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='shop_shutdown',
|
||||
field=models.BooleanField(default=False, null=True, verbose_name='Shop Shutdown (閉業)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='auto_checkin',
|
||||
field=models.BooleanField(default=False, verbose_name='Is AutoCheckin'),
|
||||
),
|
||||
]
|
||||
18
rog/migrations_backup/0014_alter_location_shop_shutdown.py
Normal file
18
rog/migrations_backup/0014_alter_location_shop_shutdown.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2.9 on 2022-06-18 09:52
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0013_auto_20220618_1847'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='shop_shutdown',
|
||||
field=models.BooleanField(default=False, verbose_name='Shop Shutdown (閉業)'),
|
||||
),
|
||||
]
|
||||
57
rog/migrations_backup/0015_auto_20220619_1611.py
Normal file
57
rog/migrations_backup/0015_auto_20220619_1611.py
Normal file
@ -0,0 +1,57 @@
|
||||
# Generated by Django 3.2.9 on 2022-06-19 07:11
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0014_alter_location_shop_shutdown'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='location',
|
||||
name='checkin_radious',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='opening_hours_fri',
|
||||
field=models.CharField(blank=True, max_length=512, null=True, verbose_name='Opening hours frinday (金曜)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='opening_hours_mon',
|
||||
field=models.CharField(blank=True, max_length=512, null=True, verbose_name='Opening hours monday (月曜)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='opening_hours_sat',
|
||||
field=models.CharField(blank=True, max_length=512, null=True, verbose_name='Opening hours saturday (土曜)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='opening_hours_sun',
|
||||
field=models.CharField(blank=True, max_length=512, null=True, verbose_name='Opening hours sunday (日曜)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='opening_hours_thu',
|
||||
field=models.CharField(blank=True, max_length=512, null=True, verbose_name='Opening hours thursday (木曜)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='opening_hours_tue',
|
||||
field=models.CharField(blank=True, max_length=512, null=True, verbose_name='Opening hours tuesday (火曜)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='opening_hours_wed',
|
||||
field=models.CharField(blank=True, max_length=512, null=True, verbose_name='Opening hours wednesday (水曜)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='photos',
|
||||
field=models.CharField(blank=True, max_length=2048, null=True, verbose_name='Photos'),
|
||||
),
|
||||
]
|
||||
21
rog/migrations_backup/0016_shapefilelocations.py
Normal file
21
rog/migrations_backup/0016_shapefilelocations.py
Normal file
@ -0,0 +1,21 @@
|
||||
# Generated by Django 3.2.9 on 2022-06-21 09:46
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0015_auto_20220619_1611'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ShapeFileLocations',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('shapefile', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Shapelayer')),
|
||||
('locid', models.IntegerField(blank=True, null=True)),
|
||||
],
|
||||
),
|
||||
]
|
||||
23
rog/migrations_backup/0017_auto_20220725_1605.py
Normal file
23
rog/migrations_backup/0017_auto_20220725_1605.py
Normal file
@ -0,0 +1,23 @@
|
||||
# Generated by Django 3.2.9 on 2022-07-25 07:05
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0016_shapefilelocations'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='cp',
|
||||
field=models.IntegerField(blank=True, null=True, verbose_name='Check Point'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='subcategory',
|
||||
field=models.CharField(blank=True, max_length=2048, null=True, verbose_name='Sub Category'),
|
||||
),
|
||||
]
|
||||
23
rog/migrations_backup/0018_auto_20220816_1616.py
Normal file
23
rog/migrations_backup/0018_auto_20220816_1616.py
Normal file
@ -0,0 +1,23 @@
|
||||
# Generated by Django 3.2.9 on 2022-08-16 07:16
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0017_auto_20220725_1605'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='sub_loc_id',
|
||||
field=models.IntegerField(blank=True, null=True, verbose_name='Sub location id'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='cp',
|
||||
field=models.FloatField(blank=True, null=True, verbose_name='Check Point'),
|
||||
),
|
||||
]
|
||||
18
rog/migrations_backup/0019_alter_location_checkin_radius.py
Normal file
18
rog/migrations_backup/0019_alter_location_checkin_radius.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2.9 on 2022-08-16 07:25
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0018_auto_20220816_1616'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='checkin_radius',
|
||||
field=models.FloatField(blank=True, default=15.0, null=True, verbose_name='Checkin radious'),
|
||||
),
|
||||
]
|
||||
23
rog/migrations_backup/0020_auto_20220816_1627.py
Normal file
23
rog/migrations_backup/0020_auto_20220816_1627.py
Normal file
@ -0,0 +1,23 @@
|
||||
# Generated by Django 3.2.9 on 2022-08-16 07:27
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0019_alter_location_checkin_radius'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='buy_point',
|
||||
field=models.FloatField(blank=True, default=0, null=True, verbose_name='buy Point'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='checkin_point',
|
||||
field=models.FloatField(blank=True, default=10, null=True, verbose_name='Checkin Point'),
|
||||
),
|
||||
]
|
||||
69
rog/migrations_backup/0021_templocation.py
Normal file
69
rog/migrations_backup/0021_templocation.py
Normal file
@ -0,0 +1,69 @@
|
||||
# Generated by Django 3.2.9 on 2022-08-17 05:48
|
||||
|
||||
from django.conf import settings
|
||||
import django.contrib.gis.db.models.fields
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0020_auto_20220816_1627'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='templocation',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('location_id', models.IntegerField(blank=True, null=True, verbose_name='Location id')),
|
||||
('sub_loc_id', models.IntegerField(blank=True, null=True, verbose_name='Sub location id')),
|
||||
('cp', models.FloatField(blank=True, null=True, verbose_name='Check Point')),
|
||||
('location_name', models.CharField(default='--- 場所をお願いします --', max_length=2048, verbose_name='Location Name')),
|
||||
('category', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Category')),
|
||||
('subcategory', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Sub Category')),
|
||||
('zip', models.CharField(blank=True, max_length=12, null=True, verbose_name='Zip code')),
|
||||
('address', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Address')),
|
||||
('prefecture', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Prefecture')),
|
||||
('area', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Area')),
|
||||
('city', models.CharField(blank=True, max_length=2048, null=True, verbose_name='City')),
|
||||
('latitude', models.FloatField(blank=True, null=True, verbose_name='Latitude')),
|
||||
('longitude', models.FloatField(blank=True, null=True, verbose_name='Latitude')),
|
||||
('photos', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Photos')),
|
||||
('videos', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Videos')),
|
||||
('webcontents', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Web Content')),
|
||||
('status', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Status')),
|
||||
('portal', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Portal')),
|
||||
('group', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Group')),
|
||||
('phone', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Phone')),
|
||||
('fax', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Fax')),
|
||||
('email', models.EmailField(blank=True, max_length=2048, null=True, verbose_name='Email')),
|
||||
('facility', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Facility')),
|
||||
('remark', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Remarks')),
|
||||
('tags', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Tags')),
|
||||
('event_name', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Event name')),
|
||||
('event_active', models.BooleanField(default=True, verbose_name='Is Event active')),
|
||||
('hidden_location', models.BooleanField(default=False, verbose_name='Is Hidden Location')),
|
||||
('auto_checkin', models.BooleanField(default=False, verbose_name='Is AutoCheckin')),
|
||||
('checkin_radius', models.FloatField(blank=True, default=15.0, null=True, verbose_name='Checkin radious')),
|
||||
('checkin_point', models.FloatField(blank=True, default=10, null=True, verbose_name='Checkin Point')),
|
||||
('buy_point', models.FloatField(blank=True, default=0, null=True, verbose_name='buy Point')),
|
||||
('evaluation_value', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Evaluation value (評価)')),
|
||||
('shop_closed', models.BooleanField(default=False, verbose_name='Shop Closed (休業)')),
|
||||
('shop_shutdown', models.BooleanField(default=False, verbose_name='Shop Shutdown (閉業)')),
|
||||
('opening_hours_mon', models.CharField(blank=True, max_length=512, null=True, verbose_name='Opening hours monday (月曜)')),
|
||||
('opening_hours_tue', models.CharField(blank=True, max_length=512, null=True, verbose_name='Opening hours tuesday (火曜)')),
|
||||
('opening_hours_wed', models.CharField(blank=True, max_length=512, null=True, verbose_name='Opening hours wednesday (水曜)')),
|
||||
('opening_hours_thu', models.CharField(blank=True, max_length=512, null=True, verbose_name='Opening hours thursday (木曜)')),
|
||||
('opening_hours_fri', models.CharField(blank=True, max_length=512, null=True, verbose_name='Opening hours frinday (金曜)')),
|
||||
('opening_hours_sat', models.CharField(blank=True, max_length=512, null=True, verbose_name='Opening hours saturday (土曜)')),
|
||||
('opening_hours_sun', models.CharField(blank=True, max_length=512, null=True, verbose_name='Opening hours sunday (日曜)')),
|
||||
('parammeters', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Parameters')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('last_updated_at', models.DateTimeField(auto_now=True)),
|
||||
('geom', django.contrib.gis.db.models.fields.MultiPointField(srid=4326)),
|
||||
('last_updated_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='temp_location_updated_user', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
23
rog/migrations_backup/0022_auto_20220822_2319.py
Normal file
23
rog/migrations_backup/0022_auto_20220822_2319.py
Normal file
@ -0,0 +1,23 @@
|
||||
# Generated by Django 3.2.9 on 2022-08-22 14:19
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0021_templocation'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='shapelayers',
|
||||
name='layerof',
|
||||
field=models.IntegerField(choices=[(1, 'templocation'), (2, 'Location_line'), (3, 'Location_polygon')], default=1),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='templocation',
|
||||
name='cp',
|
||||
field=models.FloatField(default=0, null=True, verbose_name='Check Point'),
|
||||
),
|
||||
]
|
||||
18
rog/migrations_backup/0023_alter_location_cp.py
Normal file
18
rog/migrations_backup/0023_alter_location_cp.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2.9 on 2022-08-22 14:19
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0022_auto_20220822_2319'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='cp',
|
||||
field=models.FloatField(default=0, null=True, verbose_name='Check Point'),
|
||||
),
|
||||
]
|
||||
18
rog/migrations_backup/0024_customuser_group.py
Normal file
18
rog/migrations_backup/0024_customuser_group.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2.9 on 2022-08-29 14:11
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0023_alter_location_cp'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='customuser',
|
||||
name='group',
|
||||
field=models.CharField(choices=[('G1', '大垣-初心者'), ('G2', '大垣-3時間'), ('G3', '大垣-5時間')], default='G1', max_length=2),
|
||||
),
|
||||
]
|
||||
23
rog/migrations_backup/0025_userupload.py
Normal file
23
rog/migrations_backup/0025_userupload.py
Normal file
@ -0,0 +1,23 @@
|
||||
# Generated by Django 3.2.9 on 2022-08-30 05:26
|
||||
|
||||
from django.db import migrations, models
|
||||
import rog.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rog', '0024_customuser_group'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='UserUpload',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255, verbose_name='User uploads')),
|
||||
('file', models.FileField(blank=True, upload_to=rog.models.get_file_path)),
|
||||
('uploaded_date', models.DateField(auto_now_add=True)),
|
||||
],
|
||||
),
|
||||
]
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user