Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/IN-128: IT Intake Form #41

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ MAIL_PORT=25

# IT Intake Form
APP_DEV_INTAKE_EMAIL_RECIPIENTS=admin@records.nyc.gov,pm@records.nyc.gov

IT_INTAKE_EMAIL_RECIPIENTS=admin@records.nyc.gov,it@records.nyc.gov
# File Uplaod
FILE_UPLOAD_PATH=<FULL PATH TO FILE UPLOAD DIRECTORY>

Expand Down
78 changes: 78 additions & 0 deletions app/main/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,84 @@ class EnfgForm(FlaskForm):
submit = SubmitField('Print')


class ITIntakeForm(FlaskForm):
# Submission Information
submitter_name = StringField("Submitter Name:", validators=[DataRequired()])
submitter_email = EmailField("Submitter Email:", validators=[DataRequired()])
submitter_phone = TelField("Submitter Phone:", validators=[DataRequired()])
submitter_title = StringField("Submitter Title", validators=[DataRequired()])
submitter_division = StringField(
"Submitter Division:", validators=[DataRequired()]
)

# Project Information
project_name = StringField("Name:", validators=[DataRequired()])
enhancement_or_new_project = SelectField(
"Is this a new project or an enhancement to an existing project?",
choices=PROJECT_TYPE,
validators=[DataRequired()],
)
current_project_name = StringField(
"If this is an enhancement, please provide the name of the current project:",
validators=[
RequiredIf(
enhancement_or_new_project=ENHANCEMENT,
message="You must provide the current project name if this is an enhancement",
)
],
)
project_background = TextAreaField("Background:", validators=[DataRequired()])
rationale = TextAreaField("Rationale:", validators=[DataRequired()])
project_goals = TextAreaField("Goals:", validators=[DataRequired()])
priority = SelectField("Priority:", choices=PRIORITY, validators=[DataRequired()])
completion_date = DateField(
"When do you want this project to be delivered?", validators=[DataRequired()]
)
supplemental_materials_one = FileField("Supplemental Materials:")
supplemental_materials_one_desc = StringField(
"Supplemental Materials Description: ",
validators=[RequiredIf(supplemental_materials_one != "None")],
)
supplemental_materials_two = FileField("Supplemental Materials")
supplemental_materials_two_desc = StringField(
"Supplemental Materials Description: ",
validators=[RequiredIf(supplemental_materials_two != "None")],
)
supplemental_materials_three = FileField("Supplemental Materials:")
supplemental_materials_three_desc = StringField(
"Supplemental Materials Description: ",
validators=[RequiredIf(supplemental_materials_three != "None")],
)
designated_business_owner_name = StringField(
"Designated Business Owner Name:", validators=[DataRequired()]
)
designated_business_owner_email = EmailField(
"Designated Business Owner Email:", validators=[DataRequired()]
)
designated_business_owner_phone = TelField(
"Designated Business Owner Phone:", validators=[DataRequired()]
)
designated_business_owner_title = StringField(
"Designated Business Owner Title", validators=[DataRequired()]
)
designated_business_owner_division = SelectField(
"Designated Business Owner Division:",
choices=choices.DIVISIONS,
validators=[DataRequired()],
)

# Technical Information
dependencies = TextAreaField("Does this project depend on other projects or applications? If so, please elaborate")
location_manhattan = BooleanField("31 Chambers")
location_queens = BooleanField("Queens Warehouse")
location_brooklyn = BooleanField("Bush Terminal Warehouse")

# Submit
submit = SubmitField("Submit Intake Request")




class AppDevIntakeForm(FlaskForm):
# Submission Information
submitter_name = StringField("Submitter Name:", validators=[DataRequired()])
Expand Down
121 changes: 99 additions & 22 deletions app/main/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,22 @@
from flask_login import login_required, current_user
from app.models import Users, Posts, EventPosts, Documents
from . import main
from app.main.forms import MeetingNotesForm, NewsForm, EventForm, StaffDirectorySearchForm, EnfgForm, UploadForm, AppDevIntakeForm
from app.main.utils import (create_meeting_notes,
create_news,
create_event_post,
get_users_by_division,
get_rooms_by_division,
create_document,
allowed_file,
VirusDetectedException,
scan_file,
process_documents_search,
process_posts_search,
render_email)
from app.main.forms import MeetingNotesForm, NewsForm, EventForm, StaffDirectorySearchForm, EnfgForm, UploadForm, \
AppDevIntakeForm, ITIntakeForm
from app.main.utils import (
create_meeting_notes,
create_news,
create_event_post,
get_users_by_division,
get_rooms_by_division,
create_document,
allowed_file,
VirusDetectedException,
scan_file,
process_documents_search,
process_posts_search,
render_email
)
from datetime import datetime
from io import BytesIO
import pytz
Expand Down Expand Up @@ -74,7 +77,8 @@ def news_and_updates():
sorted_tags.append((key, tags_counter[key]))

search_term = flask_request.args.get('search_term', None)
return render_template('news_and_updates.html', tags=sorted_tags, search_term=search_term, posts_counter=posts_counter)
return render_template('news_and_updates.html', tags=sorted_tags, search_term=search_term,
posts_counter=posts_counter)


@main.route('/posts/search/', methods=['GET'])
Expand Down Expand Up @@ -147,7 +151,8 @@ def meeting_notes():
# Get meeting type choices
meeting_types = choices.MEETING_TYPES[1::]

return render_template('meeting_notes.html', posts=posts, meeting_types=meeting_types, tags=sorted_tags, meeting_type_counter=meeting_type_counter)
return render_template('meeting_notes.html', posts=posts, meeting_types=meeting_types, tags=sorted_tags,
meeting_type_counter=meeting_type_counter)


@main.route('/news-and-updates/news', methods=['GET'])
Expand Down Expand Up @@ -637,6 +642,75 @@ def app_dev_intake_form():
return render_template("app_dev_intake.html", form=form, current_user=current_user)


@main.route('/it-support/it-intake-form', methods=['GET', 'POST'])
@login_required
def it_intake_form():
"""
View function to handle the IT Intake Form.

GET Request:
Returns the html template for the Intake Form

POST Request:
Handles submission of Intake form. If it is validated, redirect to the IT Support page
"""
form = ITIntakeForm()

# Pre-Fill the Submitter Information - Cannot be edited
form.submitter_name.data = current_user.name
form.submitter_email.data = current_user.email
form.submitter_phone.data = current_user.phone_number
form.submitter_title.data = current_user.title
form.submitter_division.data = current_user.division

if flask_request.method == 'GET':
# Pre-Fill the Designated Business Owner Information with the Submitters Information - Can be Edited
form.designated_business_owner_name.data = current_user.name
form.designated_business_owner_email.data = current_user.email
form.designated_business_owner_phone.data = current_user.phone_number
form.designated_business_owner_title.data = current_user.title
form.designated_business_owner_division.data = current_user.division

if form.validate_on_submit():
email = render_email(form.data, 'email/email_it_intake.html')
sender = form.submitter_email.data
recipients = current_app.config['IT_INTAKE_EMAIL_RECIPIENTS'] + [form.submitter_email.data,
form.designated_business_owner_email.data]
msg = Message(
"IT Intake Form - {project_name}".format(
project_name=form.project_name.data
),
sender=sender,
recipients=recipients,
)
msg.html = email
if form.supplemental_materials_one.data is not None:
tmp_file = BytesIO()
flask_request.files['supplemental_materials_one'].save(tmp_file)
tmp_file.seek(0)
msg.attach(filename=form.supplemental_materials_one.data.filename,
content_type=form.supplemental_materials_one.data.content_type, data=tmp_file.read())
if form.supplemental_materials_two.data is not None:
tmp_file = BytesIO()
flask_request.files['supplemental_materials_two'].save(tmp_file)
tmp_file.seek(0)
msg.attach(filename=form.supplemental_materials_two.data.filename,
content_type=form.supplemental_materials_two.data.content_type, data=tmp_file.read())
if form.supplemental_materials_three.data is not None:
tmp_file = BytesIO()
flask_request.files['supplemental_materials_three'].save(tmp_file)
tmp_file.seek(0)
msg.attach(filename=form.supplemental_materials_three.data.filename,
content_type=form.supplemental_materials_three.data.content_type, data=tmp_file.read())
mail.send(msg)
flash("Successfully submitted intake form. Please allow 5 business days for a response.")
return redirect(url_for('main.it_support'))
else:
for error in form.errors.items():
flash(error[1][0], category="danger")
return render_template("it_intake.html", form=form, current_user=current_user)


@main.route('/documents', methods=['GET'])
def documents():
"""
Expand Down Expand Up @@ -682,8 +756,10 @@ def search_documents():
document_type='policies-and-procedures',
sort_by=sort_by,
search_term=search_term,
documents_start=page_counters['policies_and_procedures']['start'],
documents_end=page_counters['policies_and_procedures']['end'])
documents_start=page_counters['policies_and_procedures'][
'start'],
documents_end=page_counters['policies_and_procedures'][
'end'])

templates_data = process_documents_search(document_type_plain_text='Templates',
document_type='templates',
Expand Down Expand Up @@ -759,15 +835,16 @@ def upload_document():
form = UploadForm()
if flask_request.method == 'POST' and form.validate_on_submit():
file = flask_request.files['file_object']
filename = secure_filename(file.filename) # use the secure version of the file name
filename = secure_filename(file.filename) # use the secure version of the file name
# Files are unique in both file title and file name, this will be used to check if a file already exists in the database
# TODO: check file uniqueness using a checksum instead of just filename
file_exists = Documents.query.filter(or_(Documents.file_name == filename, Documents.file_title == form.file_title.data)).first() or None
file_exists = Documents.query.filter(
or_(Documents.file_name == filename, Documents.file_title == form.file_title.data)).first() or None
if file_exists:
if file_exists.file_name == filename: # File with the same name already exists
if file_exists.file_name == filename: # File with the same name already exists
flash('This file has already been uploaded. Please select another file.')
return render_template('upload_document.html', form=form)
elif file_exists.file_title == form.file_title.data: # file with the same title already exists
elif file_exists.file_title == form.file_title.data: # file with the same title already exists
flash('A file with this title has already been uploaded. Please use another title.')
return render_template('upload_document.html', form=form)
elif not allowed_file(filename):
Expand All @@ -792,4 +869,4 @@ def upload_document():
division=form.division.data)
flash('Document successfully uploaded.')
return redirect(url_for('main.documents'))
return render_template('upload_document.html', form=form)
return render_template('upload_document.html', form=form)
Loading