示例#1
0
 def _validate_minimum_dates(self, dates: List[datetime.date]):
     cfg = AccessDatesValidation(**common_data.load_json("access-dates-validation.json"))
     today = datetime.date.today() - self.MIN_DAYS_LEEWAY
     for date in dates:
         if (date - today).days < cfg.MIN_DAYS:
             raise ValidationError(
                 f"Please ensure all dates are at least {cfg.MIN_DAYS} days from today."
             )
示例#2
0
from typing import List
from graphql import ResolveInfo
import graphene
from django import forms
from django.http import FileResponse
from django.core.mail import EmailMessage

from users.models import JustfixUser
from project import common_data, slack
from project.util.django_graphql_forms import DjangoFormMutation

MAX_RECIPIENTS = common_data.load_json("email-attachment-validation.json")['maxRecipients']


def email_file_response_as_attachment(
    subject: str,
    body: str,
    recipients: List[str],
    attachment: FileResponse
) -> None:
    attachment_bytes = attachment.getvalue()

    for recipient in recipients:
        msg = EmailMessage(subject=subject, body=body, to=[recipient])
        msg.attach(attachment.filename, attachment_bytes)
        msg.send()


def get_slack_notify_text(user: JustfixUser, attachment_name: str, num_recipients: int) -> str:
    return (
        f"{slack.hyperlink(text=user.first_name, href=user.admin_url)} "
示例#3
0
from django import forms

from project import common_data
from . import models

ISSUE_VALIDATION = common_data.load_json("issue-validation.json")

CUSTOM_ISSUE_MAX_LENGTH: int = ISSUE_VALIDATION['CUSTOM_ISSUE_MAX_LENGTH']
MAX_CUSTOM_ISSUES_PER_AREA: int = ISSUE_VALIDATION[
    'MAX_CUSTOM_ISSUES_PER_AREA']


class CustomIssueForm(forms.ModelForm):
    class Meta:
        model = models.CustomIssue
        fields = ['description']

    description = forms.CharField(max_length=CUSTOM_ISSUE_MAX_LENGTH)


class IssueAreaFormV2(forms.Form):
    area = forms.ChoiceField(choices=models.ISSUE_AREA_CHOICES.choices,
                             help_text="The area for the issues being set.")

    issues = forms.MultipleChoiceField(
        required=False,
        choices=models.ISSUE_CHOICES.choices,
        help_text=
        ("The issues to set. Any issues not listed, but in the same area, will be "
         "removed."))
示例#4
0
from typing import Dict, Any

from project.util import django_graphql_forms
from project import common_data
from .graphql import execute_query

FORMS_COMMON_DATA = common_data.load_json("forms.json")


class LegacyFormSubmissionError(Exception):
    pass


def fix_newlines(d: Dict[str, str]) -> Dict[str, str]:
    result = dict()
    result.update(d)
    for key in d:
        result[key] = result[key].replace("\r\n", "\n")
    return result


def get_legacy_form_submission_result(request, graphql, input):
    if request.POST.get(FORMS_COMMON_DATA["LEGACY_FORMSET_ADD_BUTTON_NAME"]):
        return None
    return execute_query(request, graphql, variables={"input":
                                                      input})["output"]


def get_legacy_form_submission(request) -> Dict[str, Any]:
    graphql = request.POST.get("graphql")
示例#5
0
from typing import Any, Dict, Optional
from django.utils.html import format_html

from project import common_data
from project.util.admin_util import admin_field


USPS_TRACKING_URL_PREFIX = common_data.load_json("loc.json")["USPS_TRACKING_URL_PREFIX"]


class SendableViaLobMixin:
    """
    This mixin can be used on any Django model that represents something that
    may possibly have been mailed via Lob.

    Note that it doesn't define any model fields itself, but *does* require that
    subclasses actually define some model fields, which are documented below. This
    is done in part because this mixin was created after a number of model classes
    having these fields were already in existence, but which all varied in small
    ways (e.g. their help text).
    """

    # This should be set to a `JSONField` of the JSON response of the API call that
    # was made to send the item that was mailed (or None if it wasn't mailed).
    lob_letter_object: Optional[Dict[str, Any]] = None

    # This should be set to a `CharField` of the USPS tracking number for the
    # thing that was mailed (or an empty string if it wasn't mailed).
    tracking_number: str = ""

    @property
示例#6
0
from django.conf import settings
from django.core.mail import send_mail

from project import common_data

RH_EMAIL_TEXT = common_data.load_json("rh.json")


def send_email_to_dhcr(first_name, last_name, address, borough, zipcode,
                       apartment_number):
    full_name = first_name + ' ' + last_name
    full_address = address + ', ' + borough
    new_line = "\n"
    send_mail(
        RH_EMAIL_TEXT['DHCR_EMAIL_SUBJECT'],
        RH_EMAIL_TEXT['DHCR_EMAIL_BODY'].replace(
            'FULL_NAME', full_name).replace(
                'FULL_ADDRESS',
                (full_address + ' ' + zipcode).strip()).replace(
                    'APARTMENT_NUMBER', apartment_number) + new_line +
        new_line + RH_EMAIL_TEXT['DHCR_EMAIL_SIGNATURE'] + new_line +
        full_name,
        settings.DHCR_EMAIL_SENDER_ADDRESS,
        settings.DHCR_EMAIL_RECIPIENT_ADDRESSES,
        fail_silently=False,
    )
示例#7
0
import datetime
from time import sleep
from typing import Any, Dict, List, Optional, Union
from dataclasses import dataclass, field
from django.utils.timezone import make_aware, utc
import requests

from project import common_data


_CONSTS = common_data.load_json("amplitude.json")

USER_ID_PREFIX: str = _CONSTS["USER_ID_PREFIX"]

# This is pre-defined by Amplitude for identify events, where we're
# not actually reporting a specific event that occurred but rather
# just updating user properties. For more information, see:
#
#     https://developers.amplitude.com/docs/batch-event-upload-api
IDENTIFY_EVENT = "$identify"

AMP_BATCH_URL = "https://api.amplitude.com/batch"

AMP_RATE_LIMIT_WAIT_SECS = 15

EPOCH = make_aware(datetime.datetime.utcfromtimestamp(0), timezone=utc)


# https://stackoverflow.com/a/11111177
def unix_time_millis(dt: datetime.datetime) -> int:
    return int((dt - EPOCH).total_seconds() * 1000.0)
示例#8
0
        (ISSUE_CHOICES.HOME__NO_HEAT, ISSUE_CHOICES.HOME__NO_HOT_WATER)),
    IssueMerger((ISSUE_CHOICES.HOME__MICE, ISSUE_CHOICES.HOME__RATS,
                 ISSUE_CHOICES.HOME__COCKROACHES)),
]

# How many lines the harassment details section of the HP action form has.
MAX_HARASSMENT_DETAILS_LINES = 11

# How many characters, on average, fit into a line in the harassment
# details section. (The font use is not monospaced.)
HARASSMENT_DETAILS_LINE_LENGTH = 60

# The most prior cases to list in EHPAs (so as not to generate an addendum).
MAX_EMERGENCY_PRIOR_CASES = 3

NYCHA_ADDRESS = common_data.load_json("nycha-address.json")

BOROUGH_COURT_LOCATIONS: Dict[str, hp.CourtLocationMC] = {
    BOROUGH_CHOICES.MANHATTAN: hp.CourtLocationMC.NEW_YORK_COUNTY,
    BOROUGH_CHOICES.BRONX: hp.CourtLocationMC.BRONX_COUNTY,
    BOROUGH_CHOICES.BROOKLYN: hp.CourtLocationMC.KINGS_COUNTY,
    BOROUGH_CHOICES.QUEENS: hp.CourtLocationMC.QUEENS_COUNTY,
    BOROUGH_CHOICES.STATEN_ISLAND: hp.CourtLocationMC.RICHMOND_COUNTY,
}

COURT_COUNTIES: Dict[str, hp.CourtCountyMC] = {
    BOROUGH_CHOICES.MANHATTAN: hp.CourtCountyMC.NEW_YORK,
    BOROUGH_CHOICES.BRONX: hp.CourtCountyMC.BRONX,
    BOROUGH_CHOICES.BROOKLYN: hp.CourtCountyMC.KINGS,
    BOROUGH_CHOICES.QUEENS: hp.CourtCountyMC.QUEENS,
    BOROUGH_CHOICES.STATEN_ISLAND: hp.CourtCountyMC.RICHMOND,
示例#9
0
from decimal import Decimal
from datetime import timedelta, date
from typing import Optional, Union, List
from enum import Enum
from django.db import models
from django.utils.crypto import get_random_string
from django.utils import timezone
from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.exceptions import ValidationError

from .hpactionvars import HarassmentAllegationsMS
from project.util.site_util import absolute_reverse
from project import common_data
from users.models import JustfixUser

COMMON_DATA = common_data.load_json("hp-action.json")

# The length, in characters, of an upload token.
UPLOAD_TOKEN_LENGTH = 40

# How long an upload token is valid.
UPLOAD_TOKEN_LIFETIME = timedelta(minutes=5)

CURRENCY_KWARGS = dict(max_digits=10, decimal_places=2)


def attr_name_for_harassment_allegation(name: str) -> str:
    return f"alleg_{name.lower()}"


class HarassmentDetails(models.Model):
示例#10
0
from django import forms

from project import common_data
from . import models

CUSTOM_ISSUE_MAX_LENGTH: int = common_data.load_json(
    "issue-validation.json")['CUSTOM_ISSUE_MAX_LENGTH']


class IssueAreaForm(forms.Form):
    area = forms.ChoiceField(choices=models.ISSUE_AREA_CHOICES.choices,
                             help_text="The area for the issues being set.")

    issues = forms.MultipleChoiceField(
        required=False,
        choices=models.ISSUE_CHOICES.choices,
        help_text=
        ("The issues to set. Any issues not listed, but in the same area, will be "
         "removed."))

    other = forms.CharField(
        required=False,
        max_length=CUSTOM_ISSUE_MAX_LENGTH,
        help_text="Any other custom issues the user wants to report.")

    def clean(self):
        cleaned_data = super().clean()
        area = cleaned_data.get('area')
        issues = cleaned_data.get('issues')

        if area and (issues is not None):
示例#11
0
from collections import defaultdict
from django import forms
from django.core.validators import RegexValidator

from project import common_data
from project.forms import (
    YesNoRadiosField,
    ensure_at_least_one_is_true,
    DynamicallyRequiredFieldsMixin,
)
from issues.models import ISSUE_CHOICES, get_issue_area
from onboarding.models import OnboardingInfo
from loc.landlord_info_mutation import BaseLandlordExtraInfoForm
from . import models

EMERGENCY_HPA_ISSUE_LIST = common_data.load_json(
    "emergency-hpa-issue-list.json")

EMERGENCY_HPA_CHOICES = [(value, ISSUE_CHOICES.get_label(value))
                         for value in EMERGENCY_HPA_ISSUE_LIST]

EMERGENCY_HPA_ISSUES_BY_AREA: Dict[str, List[str]] = defaultdict(list)

for _issue in EMERGENCY_HPA_ISSUE_LIST:
    EMERGENCY_HPA_ISSUES_BY_AREA[get_issue_area(_issue)].append(_issue)
del _issue


class FeeWaiverIncomeForm(forms.ModelForm):
    class Meta:
        model = models.FeeWaiverDetails
        fields = [