mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 19:01:39 -04:00
Refusing to rename Tag or move Channel when files are refreshing.
This commit is contained in:
parent
d8ef7e175e
commit
6fe8a7b704
5 changed files with 67 additions and 28 deletions
|
|
@ -757,7 +757,7 @@ export function ChannelsPage() {
|
|||
|
||||
const headers = [
|
||||
{key: 'name', text: 'Name', sortBy: 'name', width: 8},
|
||||
{key: 'tag', text: 'Tag', sortBy: 'tag', width: 2},
|
||||
{key: 'tag', text: 'Tag', sortBy: 'tag_name', width: 2},
|
||||
{key: 'video_count', text: 'Videos', sortBy: 'video_count', width: 2},
|
||||
{key: 'download_frequency', text: 'Download Frequency', sortBy: 'minimum_frequency', width: 2},
|
||||
{key: 'size', text: 'Size', sortBy: 'size', width: 2},
|
||||
|
|
|
|||
|
|
@ -5,11 +5,12 @@ from typing import List, Dict, Union
|
|||
from sqlalchemy import or_, func, desc, asc
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from wrolpi import flags
|
||||
from wrolpi.common import run_after, logger, \
|
||||
get_media_directory, wrol_mode_check
|
||||
from wrolpi.db import get_db_curs, optional_session, get_db_session
|
||||
from wrolpi.downloader import save_downloads_config, download_manager
|
||||
from wrolpi.errors import UnknownDirectory, APIError, ValidationError
|
||||
from wrolpi.errors import UnknownDirectory, APIError, ValidationError, RefreshConflict
|
||||
from .. import schema
|
||||
from ..common import check_for_channel_conflicts
|
||||
from ..errors import UnknownChannel, ChannelDirectoryConflict
|
||||
|
|
@ -257,6 +258,9 @@ async def tag_channel(tag_name: str, directory: pathlib.Path | None, channel_id:
|
|||
Move the Channel to the new directory, if provided."""
|
||||
from wrolpi.tags import Tag
|
||||
|
||||
if directory and flags.refreshing.is_set():
|
||||
raise RefreshConflict('Refusing to move channel while file refresh is in progress')
|
||||
|
||||
channel = Channel.find_by_id(channel_id, session=session)
|
||||
|
||||
if tag_name:
|
||||
|
|
|
|||
|
|
@ -169,3 +169,9 @@ class InvalidDirectory(APIError):
|
|||
code = 'INVALID_DIRECTORY'
|
||||
message = 'Directory is not valid or impossible'
|
||||
status_code = HTTPStatus.BAD_REQUEST
|
||||
|
||||
|
||||
class RefreshConflict(APIError):
|
||||
code = 'REFRESH_CONFLICT'
|
||||
message = 'Not possible during file refresh'
|
||||
status_code = HTTPStatus.CONFLICT
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@ from sqlalchemy import Column, Integer, String, ForeignKey, BigInteger
|
|||
from sqlalchemy.exc import IntegrityError
|
||||
from sqlalchemy.orm import relationship, Session
|
||||
|
||||
from wrolpi import dates
|
||||
from wrolpi import dates, flags
|
||||
from wrolpi.common import ModelHelper, Base, logger, ConfigFile, get_media_directory, background_task, run_after, \
|
||||
register_refresh_cleanup, get_relative_to_media_directory, is_valid_hex_color, walk, INVALID_FILE_CHARS
|
||||
get_relative_to_media_directory, is_valid_hex_color, walk, INVALID_FILE_CHARS
|
||||
from wrolpi.dates import TZDateTime
|
||||
from wrolpi.db import optional_session, get_db_curs
|
||||
from wrolpi.errors import UnknownTag, UsedTag, InvalidTag, FileGroupAlreadyTagged
|
||||
from wrolpi.errors import UnknownTag, UsedTag, InvalidTag, FileGroupAlreadyTagged, RefreshConflict
|
||||
from wrolpi.vars import PYTEST
|
||||
|
||||
logger = logger.getChild(__name__)
|
||||
|
|
@ -150,6 +150,26 @@ class Tag(ModelHelper, Base):
|
|||
"""Returns True if this Tag has been used with any FileGroups or Zim Entries."""
|
||||
return bool(self.tag_files or self.tag_zim_entries)
|
||||
|
||||
def update_tag(self, name: str, color: str, session: Session):
|
||||
"""Change name/color of tag. Ensures safeness of new values, checks for conflicts."""
|
||||
if ',' in name:
|
||||
raise InvalidTag('Tag name cannot have comma')
|
||||
if not is_valid_hex_color(color):
|
||||
raise InvalidTag('Tag color is invalid')
|
||||
|
||||
# Replace forward-slash (linux directories) with unicode Big Solidus (U+29F8)
|
||||
name = name.replace('/', '⧸')
|
||||
name = INVALID_FILE_CHARS.sub('', name)
|
||||
|
||||
if Tag.get_by_name(name, session):
|
||||
raise InvalidTag('Tag name already taken')
|
||||
|
||||
if flags.refreshing.is_set():
|
||||
raise RefreshConflict('Refusing to rename tag while file refresh is in progress')
|
||||
|
||||
self.name = name
|
||||
self.color = color
|
||||
|
||||
|
||||
class TagsConfig(ConfigFile):
|
||||
file_name = 'tags.yaml'
|
||||
|
|
@ -375,27 +395,16 @@ def get_tags() -> List[dict]:
|
|||
@optional_session
|
||||
@run_after(save_tags_config)
|
||||
def upsert_tag(name: str, color: str, tag_id: int = None, session: Session = None) -> Tag:
|
||||
if ',' in name:
|
||||
raise InvalidTag('Tag name cannot have comma')
|
||||
if not is_valid_hex_color(color):
|
||||
raise InvalidTag('Tag color is invalid')
|
||||
|
||||
# Replace forward-slash (linux directories) with unicode Big Solidus (U+29F8)
|
||||
name = name.replace('/', '⧸')
|
||||
name = INVALID_FILE_CHARS.sub('', name)
|
||||
|
||||
if tag_id:
|
||||
tag = session.query(Tag).filter_by(id=tag_id).one_or_none()
|
||||
if not tag:
|
||||
raise UnknownTag(f'Cannot find tag with id={tag_id}')
|
||||
tag.name = name
|
||||
tag.color = color
|
||||
tag = Tag.find_by_id(tag_id, session)
|
||||
tag.update_tag(name, color, session)
|
||||
tag.flush()
|
||||
else:
|
||||
tag = Tag(name=name, color=color)
|
||||
tag = Tag()
|
||||
tag.update_tag(name, color, session)
|
||||
session.add(tag)
|
||||
|
||||
try:
|
||||
session.flush([tag])
|
||||
session.commit()
|
||||
except IntegrityError as e:
|
||||
# Conflicting name
|
||||
|
|
@ -410,14 +419,10 @@ def upsert_tag(name: str, color: str, tag_id: int = None, session: Session = Non
|
|||
|
||||
@optional_session
|
||||
def delete_tag(tag_id: int, session: Session = None):
|
||||
tag: Tag = session.query(Tag).filter_by(id=tag_id).one_or_none()
|
||||
tag = Tag.find_by_id(tag_id, session)
|
||||
|
||||
if not tag:
|
||||
raise UnknownTag(f'Cannot find tag {tag_id}')
|
||||
|
||||
if tag.tag_files:
|
||||
count = len(tag.tag_files)
|
||||
raise UsedTag(f'Cannot delete {tag.name} it is used by {count} files!')
|
||||
if tag.has_relations():
|
||||
raise UsedTag(f'Cannot delete {tag.name} it is used')
|
||||
|
||||
session.delete(tag)
|
||||
session.commit()
|
||||
|
|
|
|||
|
|
@ -339,6 +339,7 @@ async def test_invalid_tag(test_async_client, test_session, test_directory):
|
|||
@pytest.mark.asyncio
|
||||
async def test_tags_directory(test_async_client, test_session, test_directory, tag_factory, video_factory,
|
||||
example_pdf):
|
||||
"""Test that Tag Directory is synchronized with database."""
|
||||
readme = test_directory / 'tags/README.txt'
|
||||
|
||||
# Should be deleted on sync.
|
||||
|
|
@ -436,3 +437,26 @@ async def test_tags_directory(test_async_client, test_session, test_directory, t
|
|||
# Only three FileGroups were created. Tags Directory files are ignored during refresh.
|
||||
await files_lib.refresh_files()
|
||||
assert test_session.query(FileGroup).count() == 3
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_update_tag(test_async_client, test_session, test_directory, video_factory, tag_factory):
|
||||
"""Linked files in the Tag Directory are moved when the tag is renamed."""
|
||||
# Create tagged Video.
|
||||
tag = tag_factory()
|
||||
video_factory(title='video', tag_names=[tag.name])
|
||||
test_session.commit()
|
||||
|
||||
# Video file is linked in tag directory.
|
||||
assert (test_directory / 'tags').is_dir()
|
||||
assert (test_directory / 'videos/NO CHANNEL/video.mp4').is_file()
|
||||
assert (test_directory / 'tags/one/video.mp4').is_file()
|
||||
|
||||
# Invalid characters are replaced during rename.
|
||||
tags.upsert_tag('new/name%', tag.color, tag.id)
|
||||
|
||||
# Video file was moved.
|
||||
assert (test_directory / 'tags').is_dir()
|
||||
assert (test_directory / 'videos/NO CHANNEL/video.mp4').is_file()
|
||||
assert not (test_directory / 'tags/one/video.mp4').exists()
|
||||
assert (test_directory / 'tags/new⧸name/video.mp4').is_file()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue