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

Task: Content Spacing Correction #801

Merged
merged 10 commits into from
Oct 5, 2023
15 changes: 8 additions & 7 deletions src/api/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from api.store.common import create_pdf_from_rich_text, sign_mou
from api.store.utils import get_user_from_context
from database.models import Policy
from task_queue.events_nudge.cadmin_events_nudge import generate_event_list_for_community, send_events_report
from task_queue.nudges.cadmin_events_nudge import generate_event_list_for_community, send_events_report
from api.store.utils import get_community, get_user
from celery import shared_task
from api.store.download import DownloadStore
Expand All @@ -19,16 +19,17 @@
from django.utils.timezone import utc
from django.db.models import Count

from task_queue.events_nudge.user_event_nudge import prepare_user_events_nudge
from task_queue.nudges.user_event_nudge import prepare_user_events_nudge


def generate_csv_and_email(data, download_type, community_name=None, email=None):
def generate_csv_and_email(data, download_type, community_name=None, email=None,filename=None):
response = HttpResponse(content_type="text/csv")
now = datetime.datetime.now().strftime("%Y%m%d")
if not community_name:
filename = "all-%s-data-%s.csv" % (download_type, now)
else:
filename = "%s-%s-data-%s.csv" % (community_name, download_type, now)
if not filename:
if not community_name:
filename = "all-%s-data-%s.csv" % (download_type, now)
else:
filename = "%s-%s-data-%s.csv" % (community_name, download_type, now)
writer = csv.writer(response)
for row in data:
writer.writerow(row)
Expand Down
Empty file.
114 changes: 114 additions & 0 deletions src/task_queue/database_tasks/contents_spacing_correction.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import csv
import datetime
from django.apps import apps
from sentry_sdk import capture_message
from _main_.utils.emailer.send_email import send_massenergize_email_with_attachments
from api.utils.constants import DATA_DOWNLOAD_TEMPLATE
from database import models as db_models
from django.http import HttpResponse
import re


FEATURE_FLAG_KEY = "update-html-format-feature-flag"
PATTERNS = ["<p><br></p>", "<p>.</p>", "<p>&nbsp;</p>", "<br />."]
PATTERN = "|".join(re.escape(p) for p in PATTERNS)

"""
This File is used to fix spacing for both universal contents(contents not tied to a community) and content tied to a community.
There are two parts to this:
1. Generate a report of the contents that need to be fixed with the following information
a. Community: the community the content belongs to
b. Content type: whether content is an Action/Event/Testimonial etc.
c. Item name: the name or title of the content
d. Field name: the field name of the content to be corrected
e. Count: the number of occurrences of spacing in the content.
2. Fix the spacing in the database.
"""

def write_to_csv(data):
response = HttpResponse(content_type="text/csv")
writer = csv.DictWriter(response, fieldnames=["Community", "Content Type", "Item Name", "Field Name", "Count"])
writer.writeheader()
for row in data:
writer.writerow(row)
return response.content


def get_community(instance):
if instance and hasattr(instance, "community"):
return instance.community.name if instance.community else ""
elif instance and hasattr(instance, "primary_community"):
return instance.primary_community.name if instance.primary_community else ""

Copy link
Contributor

@BradHN1 BradHN1 Oct 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else return "N/A"
in case the model doesn't have a community

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed


def get_model_instances(model_name, app_label):
model = apps.get_model(app_label=app_label, model_name=model_name)
filter_args = {} if model_name == "PastEvent" else {"is_deleted": False}
model_instances = model.objects.filter(**filter_args)
return model_instances


def auto_correct_spacing(instance, field_name, field_value):
for pattern in PATTERNS:
field_value = field_value.replace(pattern, "")
setattr(instance, field_name, field_value)
instance.save()



def is_feature_enabled(instance):
communities = db_models.Community.objects.filter(is_deleted=False)
flag = db_models.FeatureFlag.objects.filter(key=FEATURE_FLAG_KEY).first()
if not flag or not flag.enabled():
return False
enabled_communities = flag.enabled_communities(communities)
if hasattr(instance, "community"):
if not instance.community or instance.community in enabled_communities:
return True
elif hasattr(instance, "primary_community"):
if not instance.primary_community or instance.primary_community in enabled_communities:
return True
return False


def process_spacing_data(task=None):
try:
data = []
models = apps.get_models()
for model in models:
app_label = model._meta.app_label
for field in model._meta.fields:
if field.__class__.__name__ == "TextField" and app_label in ["database"]:
model_name = model.__name__
field_name = field.name
model_instances = get_model_instances(model_name, app_label)
for instance in model_instances:
field_value = getattr(instance, field_name)
if field_value:
count = len(re.findall(PATTERN, field_value))
if count > 0:
if is_feature_enabled(instance):
auto_correct_spacing(instance, field_name, field_value)

data.append({
"Community": get_community(instance),
"Content Type": model_name,
"Item Name": instance.name if hasattr(model, "name") else instance.title,
"Field Name": field_name,
"Count": count,
})

if len(data) > 0:
report = write_to_csv(data)
temp_data = {'data_type': "Content Spacing", "name":task.creator.full_name if task.creator else "admin"}
file_name = "Content-Spacing-Report-{}.csv".format(datetime.datetime.now().strftime("%Y-%m-%d"))
send_massenergize_email_with_attachments(DATA_DOWNLOAD_TEMPLATE,temp_data,[task.creator.email], report, file_name)

return True
except Exception as e:
print(str(e))
capture_message(str(e), level="error")
BradHN1 marked this conversation as resolved.
Show resolved Hide resolved
return False



7 changes: 5 additions & 2 deletions src/task_queue/jobs.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

from task_queue.events_nudge.cadmin_events_nudge import send_events_nudge
from task_queue.events_nudge.user_event_nudge import prepare_user_events_nudge
from task_queue.database_tasks.contents_spacing_correction import process_spacing_data
from task_queue.nudges.cadmin_events_nudge import send_events_nudge
from task_queue.nudges.user_event_nudge import prepare_user_events_nudge
from task_queue.nudges.postmark_sender_signature import collect_and_create_signatures
from task_queue.views import super_admin_nudge, create_snapshots, send_admin_mou_notification

Expand All @@ -9,6 +10,7 @@
1- Do not update the dictionary keys.
2- Do not delete dictionary item if there is a task attached to it.
3- Make sure to wrap your function in try except and return True or False
4- All tasks from Oct 5th 2023 should have at least one argument(task) which is the task instance.

You can only add new items to the dictionary.
"""
Expand All @@ -19,4 +21,5 @@
"User Event Nudge": prepare_user_events_nudge,
"Create Community Snapshots": create_snapshots,
"Postmark Sender Signature": collect_and_create_signatures,
"Process Content Spacing": process_spacing_data,
}
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ def prepare_events_email_data(events):
# this is the function called in jobs.py


def send_events_nudge():
def send_events_nudge(task=None):
try:
admins_emailed=[]
flag = FeatureFlag.objects.get(key=WEEKLY_EVENT_NUDGE)
Expand Down
2 changes: 1 addition & 1 deletion src/task_queue/nudges/postmark_sender_signature.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
COMMUNITY_EMAIL_SENDER_SIGNATURE_FF = "community-email-sender-signature-feature-flag"


def collect_and_create_signatures():
def collect_and_create_signatures(task=None):
flag = FeatureFlag.objects.filter(key=COMMUNITY_EMAIL_SENDER_SIGNATURE_FF).first()
if not flag or not flag.enabled():
return False
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ def get_user_events(notification_dates, community_events):
nudge is requested on demand by a cadmin on user portal.
'''
# Entry point
def prepare_user_events_nudge(email=None, community_id=None):
def prepare_user_events_nudge(task=None,email=None, community_id=None):
try:
if email and community_id:
all_community_events = get_community_events(community_id)
Expand Down
2 changes: 1 addition & 1 deletion src/task_queue/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def run_some_task(self, task_id):
if func:
task.status= "SCHEDULED"
task.save()
res = func()
res = func(task)
task.status = "SUCCEEDED" if res else "FAILED"
else:
task.status = "FAILED"
Expand Down
6 changes: 3 additions & 3 deletions src/task_queue/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def query_db():
}


def super_admin_nudge():
def super_admin_nudge(task=None):
"""
Send a nudge to super admins.
"""
Expand Down Expand Up @@ -363,7 +363,7 @@ def _create_community_timestamp(community, prim_dict):
snapshot.save()


def create_snapshots():
def create_snapshots(task=None):
try:
communities = Community.objects.filter(is_deleted=False) #is_published, is_demo =False
users = UserProfile.objects.filter(is_deleted=False)
Expand Down Expand Up @@ -408,7 +408,7 @@ def update_records(**kwargs):


# Function to send MOU notifications to community admins
def send_admin_mou_notification():
def send_admin_mou_notification(task=None):
"""
This function sends MOU (Memorandum of Understanding) notifications to all active community admins. It retrieves the last MOU record signed by each admin, checks if it's been over a year since they last signed, and sends an email notification if necessary. A timestamp of the latest notification is added to the policy record. If the admin has never been notified, then the function will record the current timestamp as the first notification. If there is no previous MOU record for the admin, the function assumes that they have never signed the MOU before and sends an MOU email to the admin.
"""
Expand Down