<commit_before>import datetime
from typing import Optional

from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.db.models.signals import post_save

from accounts.models import Account, AccountTeam
from jobs.models import Job, JobMethod
from manager.helpers import EnumChoice
from users.models import User


class Project(models.Model):
    """
    A project.

    Projects are always owned by an account.
    """

    account = models.ForeignKey(
        Account,
        on_delete=models.CASCADE,
        related_name="projects",
        null=False,
        blank=False,
        help_text="Account that the project belongs to.",
    )

    creator = models.ForeignKey(
        User,
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="projects_created",
        help_text="The user who created the project.",
    )

    created = models.DateTimeField(
        auto_now_add=True, help_text="The time the project was created."
    )

    name = models.SlugField(
        null=False,
        blank=False,
        help_text="Name of the project. Lowercase only and unique for the account. "
        "Will be used in URLS e.g. https://hub.stenci.la/awesome-org/great-project.",
    )

    title = models.CharField(
        null=True,
        blank=True,
        max_length=256,
        help_text="Title of the project to display in its profile.",
    )

    temporary = models.BooleanField(
        default=False, help_text="Is the project temporary?"
    )

    public = models.BooleanField(
        default=True, help_text="Is the project publicly visible?"
    )

    description = models.TextField(
        null=True, blank=True, help_text="Brief description of the project."
    )

    theme = models.TextField(
        null=True,
        blank=True,
        help_text="The name of the theme to use as the default when generating content for this project."
        # See note for the `Account.theme` field for why this is a TextField.
    )

    main = models.TextField(
        null=True, blank=True, help_text="Path of the main file of the project",
    )

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=["account", "name"], name="%(class)s_unique_account_name"
            )
        ]

    TEMPORARY_PROJECT_LIFESPAN = datetime.timedelta(days=1)

    def __str__(self):
        return self.name

    @property
    def scheduled_deletion_time(self) -> Optional[datetime.datetime]:
        """
        Get the scheduled deletion time of a temporary project.
        """
        return (
            (self.created + Project.TEMPORARY_PROJECT_LIFESPAN)
            if self.temporary
            else None
        )

    def get_main(self):
        """
        Get the main file for the project.

        The main file can be designated by the user,
        but if not them defaults to main.* or README.*
        if those are present.
        """
        if self.main:
            try:
                self.files.get(path=self.main, current=True)
            except ObjectDoesNotExist:
                return None
        else:
            # TODO
            return None

    def get_theme(self) -> str:
        """Get the theme for the project."""
        return self.theme or self.account.theme

    def clean(self, user: User) -> Job:
        """
        Clean the project's working directory.

        Removes all files from the working directory.
        In the future, this may be smarter and only remove
        those files that are orphaned (i.e. not registered as part of the pipeline)
        """
        return Job.objects.create(
            description="Clean project '{0}'".format(self.name),
            project=self,
            creator=user,
            method=JobMethod.clean.name,
            params=dict(project=self.id),
        )

    def pull(self, user: User) -> Job:
        """<commit_msg>fix(Projects): Fix getting of main file<commit_after>import datetime
from typing import Optional

from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.db.models import Q
from django.db.models.signals import post_save

from accounts.models import Account, AccountTeam
from jobs.models import Job, JobMethod
from manager.helpers import EnumChoice
from users.models import User


class Project(models.Model):
    """
    A project.

    Projects are always owned by an account.
    """

    account = models.ForeignKey(
        Account,
        on_delete=models.CASCADE,
        related_name="projects",
        null=False,
        blank=False,
        help_text="Account that the project belongs to.",
    )

    creator = models.ForeignKey(
        User,
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="projects_created",
        help_text="The user who created the project.",
    )

    created = models.DateTimeField(
        auto_now_add=True, help_text="The time the project was created."
    )

    name = models.SlugField(
        null=False,
        blank=False,
        help_text="Name of the project. Lowercase only and unique for the account. "
        "Will be used in URLS e.g. https://hub.stenci.la/awesome-org/great-project.",
    )

    title = models.CharField(
        null=True,
        blank=True,
        max_length=256,
        help_text="Title of the project to display in its profile.",
    )

    temporary = models.BooleanField(
        default=False, help_text="Is the project temporary?"
    )

    public = models.BooleanField(
        default=True, help_text="Is the project publicly visible?"
    )

    description = models.TextField(
        null=True, blank=True, help_text="Brief description of the project."
    )

    theme = models.TextField(
        null=True,
        blank=True,
        help_text="The name of the theme to use as the default when generating content for this project."
        # See note for the `Account.theme` field for why this is a TextField.
    )

    main = models.TextField(
        null=True, blank=True, help_text="Path of the main file of the project",
    )

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=["account", "name"], name="%(class)s_unique_account_name"
            )
        ]

    TEMPORARY_PROJECT_LIFESPAN = datetime.timedelta(days=1)

    def __str__(self):
        return self.name

    @property
    def scheduled_deletion_time(self) -> Optional[datetime.datetime]:
        """
        Get the scheduled deletion time of a temporary project.
        """
        return (
            (self.created + Project.TEMPORARY_PROJECT_LIFESPAN)
            if self.temporary
            else None
        )

    def get_main(self):
        """
        Get the main file for the project.

        The main file can be designated by the user
        (using the `main` field as the path). If no file
        matches that path (e.g. because it was removed),
        or if `main` was never set, then this defaults to the
        most recently modified file with path `main.*` or `README.*`
        if those are present.
        """
        if self.main:
            try:
                return self.files.get(path=self.main, current=True)
            except ObjectDoesNotExist:
                pass

        candidates = self.files.filter(
            Q(path__startswith="main.") | Q(path__startswith="README.")
        ).order_by("-modified")
        if len(candidates):
            return candidates[0]

        return None

    def get_theme(self) -> str:
        """Get the theme for the project."""
        return self.theme or self.account.theme

    def clean(self, user: User) -> Job:
        """
        Clean the project's working directory.

        Removes all files from the working directory.
        In the future, this may be smarter and only remove
        those files that are orphaned (i.e. not registered as part of the pipeline)
        """
        return Job.objects.create(
            description="Clean project '{0}'".format(self.name),
            project=self,
            creator=user,
            method=JobMethod.clean.name,
            params=dict(project=self.id),
        )

    def pull(self, user: User) -> Job:
        """
{'fraction_non_alphanumeric': 0.08841902931283037, 'fraction_numerical': 0.0013214800576645844, 'mean_word_length': 2.1296992481203008, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 11, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5268253', 'n_tokens_mistral': 2302, 'n_tokens_neox': 2236, 'n_words': 705}