Skip to content
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
9 changes: 0 additions & 9 deletions .env.example
Comment thread
ankitamk14 marked this conversation as resolved.

This file was deleted.

20 changes: 10 additions & 10 deletions forums/settings.py
Comment thread
ankitamk14 marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -114,16 +114,16 @@
'HOST': '',
'PORT': '', # Set to empty string for default.
},
'cdeep': {
'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
'NAME': 'CDEEP', # Or path to database file if using sqlite3.
# The following settings are not used with sqlite3:
'USER': os.getenv("DB_USER"),
'PASSWORD': os.getenv("DB_PASSWORD"),
# Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
'HOST': '',
'PORT': '', # Set to empty string for default.
},
#'cdeep': {
# 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
# 'NAME': 'CDEEP', # Or path to database file if using sqlite3.
# # The following settings are not used with sqlite3:
# 'USER': os.getenv("DB_USER"),
# 'PASSWORD': os.getenv("DB_PASSWORD"),
# # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
# 'HOST': '',
# 'PORT': '', # Set to empty string for default.
#},
}

# Password validation
Expand Down
12 changes: 6 additions & 6 deletions forums/views.py
Comment thread
ankitamk14 marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.http import HttpResponseRedirect, HttpResponse
from django.contrib.auth import login, logout
from django.shortcuts import render_to_response
from django.shortcuts import render
from django.template.context_processors import csrf

from forums.forms import UserLoginForm
Expand Down Expand Up @@ -29,7 +29,7 @@ def user_login(request):
'resetpasssucs': resetpasssucs
}
context.update(csrf(request))
return render_to_response('forums/templates/user-login.html', context)
return render(request,'forums/templates/user-login.html', context)
else:
return HttpResponseRedirect('/')

Expand All @@ -49,7 +49,7 @@ def updatepassword(request):
confirm = request.POST['confirm_new_password']
if new_password == "" or confirm == "":
context['empty'] = True
return render_to_response("update-password.html", context)
return render(request,"update-password.html", context)
if new_password == confirm:
user.set_password(new_password)
user.save()
Expand All @@ -61,14 +61,14 @@ def updatepassword(request):
return HttpResponseRedirect('/')
else:
context['no_match'] = True
return render_to_response("forums/templates/update-password.html", context)
return render(request,"forums/templates/update-password.html", context)
else:
return render_to_response("forums/templates/update-password.html", context)
return render(request,"forums/templates/update-password.html", context)
else:
form = UserLoginForm()
context['form'] = form
context['for_update_password'] = True
return render_to_response('website/templates/index.html', context)
return render(request,'website/templates/index.html', context)

def robots_txt(request):
with open('robots.txt', 'r') as f:
Expand Down
116 changes: 116 additions & 0 deletions seed_spam_rules.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Script to seed the database with predefined spam rules
import os
import django

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "forums.settings")
django.setup()

from django.db.models import Q
from website.models import SpamRule



def seed_spam_rules():
rules = {
# Certification/Exam dump patterns
"Certification/Exam Spam": {
"score": 30,
"type": SpamRule.KEYWORD,
"patterns": [
r"exam\s+dumps?", r"braindumps?", r"practice\s+test",
r"certification\s+exam", r"test\s+preparation",
r"exam\s+questions?", r"study\s+guides?",
r"pdf\s+\+\s+testing\s+engine", r"testing\s+engine",
r"exam\s+prep", r"mock\s+exam", r"real\s+exam",
r"dumps\s+pdf", r"braindump"
],
},

# Promotional spam
"Promotional Spam": {
"score": 25,
"type": SpamRule.KEYWORD,
"patterns": [
r"click\s+here", r"join\s+now", r"limited\s+time",
r"discount", r"coupon\s+code", r"20%\s+off",
r"free\s+download", r"get\s+certified",
r"unlock\s+your\s+career", r"master\s+the",
r"boost\s+your\s+career", r"cert20",
r"at\s+checkout", r"special\s+offer",
],
},

# Suspicious domains
"Suspicious Domain": {
"score": 35,
"type": SpamRule.DOMAIN,
"patterns": [
r"dumpscafe\.com", r"certsout\.com", r"mycertshub\.com",
r"vmexam\.com", r"kissnutra\.com", r"dumps.*\.com",
r"cert.*\.com", r"exam.*\.com",
],
},

# Generic business language
"Business/Career Spam": {
"score": 15,
"type": SpamRule.KEYWORD,
"patterns": [
r"attests\s+to\s+your\s+proficiency",
r"esteemed\s+(?:accreditation|certification|credential)",
r"valuable\s+asset\s+to\s+companies",
r"demonstrates\s+your\s+ability",
r"comprehensive\s+study\s+(?:tools|materials)",
r"interactive\s+practice\s+tests",
r"real\s+exam\s+questions",
r"actual\s+exam\s+questions",
r"validated\s+by\s+.*certification",
r"urgently\s+need\s+experts",
],
},

# Gaming content
"Gaming Spam": {
"score": 20,
"type": SpamRule.KEYWORD,
"patterns": [
r"spacebar\s+clicker", r"clicker\s+game",
r"addictive\s+game", r"upgrades\s+available",
r"instant\s+rewards",
],
},

# Health/Supplement spam
"Health Spam": {
"score": 22,
"type": SpamRule.KEYWORD,
"patterns": [
r"vitalit[äa]t", r"nahrungserg[äa]nzungsmittel",
r"libido", r"fruchtbarkeit", r"energie",
r"hormonelle\s+balance", r"perforan",
],
},
}

inserted, skipped = 0, 0
for note, config in rules.items():
for pattern in config["patterns"]:
exists = SpamRule.objects.filter(
Q(pattern=pattern) & Q(type=config["type"])
).exists()
if not exists:
SpamRule.objects.create(
type=config["type"],
pattern=pattern,
score=config["score"],
notes=note,
)
inserted += 1
else:
skipped += 1

print(f"✅ Inserted {inserted} new rules, skipped {skipped} existing ones.")


# Run it
seed_spam_rules()
24 changes: 24 additions & 0 deletions static/website/js/thread-user.js
Comment thread
ankitamk14 marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,30 @@ bkLib.onDomLoaded(function() {
questionNicEditor.setPanel('questionNicPanel');
questionNicEditor.addInstance('questionInstance');
});
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
const csrftoken = getCookie('csrftoken');

$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});


$(document).ready(function() {
/*
Expand Down
73 changes: 44 additions & 29 deletions website/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,34 @@
minutes = ()
seconds = ()

# Pre-fetch FOSS ids shown on homepage
foss_ids = list(
FossCategory.objects.using('spoken')
.filter(show_on_homepage=1)
.values_list('id', flat=True) # get ids only
)


class NewQuestionForm(forms.Form):
category = forms.ChoiceField(choices=[('', 'Select a Category'), ] + list(TutorialResources.objects.filter(
Q(status=1) | Q(status=2), language__name='English',tutorial_detail__foss__show_on_homepage=1).values('tutorial_detail__foss__foss').order_by(
'tutorial_detail__foss__foss').values_list('tutorial_detail__foss__foss',
'tutorial_detail__foss__foss').distinct()),
widget=forms.Select(attrs={}), required=True, error_messages={'required': 'State field is required.'})
category = forms.ChoiceField(
choices=[('', 'Select a Category')] +
list(
TutorialResources.objects.using('spoken')
.filter(
Q(status__in=[1, 2]), # cleaner than Q(status=1)|Q(status=2)
language_id=22, # use id instead of name
tutorial_detail__foss_id__in=foss_ids
)
.values('tutorial_detail__foss__foss')
.order_by('tutorial_detail__foss__foss')
.values_list('tutorial_detail__foss__foss', 'tutorial_detail__foss__foss')
.distinct()
),
widget=forms.Select(attrs={}),
required=True,
error_messages={'required': 'State field is required.'}
)

title = forms.CharField(max_length=200)
body = forms.CharField(widget=forms.Textarea())

Expand All @@ -24,49 +45,43 @@ def __init__(self, *args, **kwargs):

select_min = kwargs.pop('minute_range', None)
select_sec = kwargs.pop('second_range', None)

super(NewQuestionForm, self).__init__(*args, **kwargs)
tutorial_choices = (
("Select a Tutorial", "Select a Tutorial"),
)
# check minute_range, secpnd_range coming from spoken website
# user clicks on post question link through website
if (select_min is None and select_sec is None):
minutes = (
(select_min, select_min),
)
seconds = (
(select_sec, select_sec),
)

tutorial_choices = (("Select a Tutorial", "Select a Tutorial"),)

# Set minutes & seconds
if select_min is None and select_sec is None:
minutes = ((select_min, select_min),)
seconds = ((select_sec, select_sec),)
else:
minutes = (
("", "min"),
)
seconds = (
("", "sec"),
)
minutes = (("", "min"),)
seconds = (("", "sec"),)

# Handle category logic
if not category and args and 'category' in args[0] and args[0]['category']:
category = args[0]['category']
if FossCategory.objects.filter(foss=category).exists():

if FossCategory.objects.using('spoken').filter(foss=category).exists():
self.fields['category'].initial = category
tutorials = TutorialDetails.objects.using('spoken').filter(foss__foss=category)
for tutorial in tutorials:
tutorial_choices += ((tutorial.tutorial, tutorial.tutorial),)

self.fields['tutorial'] = forms.CharField(widget=forms.Select(choices=tutorial_choices))

if TutorialDetails.objects.using('spoken').filter(tutorial=selecttutorial).exists():
self.fields['tutorial'].initial = selecttutorial

self.fields['minute_range'] = forms.CharField(widget=forms.Select(choices=minutes))
self.fields['second_range'] = forms.CharField(widget=forms.Select(choices=seconds))
else:
self.fields['minute_range'] = forms.CharField(widget=forms.Select(choices=minutes))
self.fields['second_range'] = forms.CharField(widget=forms.Select(choices=seconds))
self.fields['minute_range'] = forms.CharField(widget=forms.Select(choices=minutes))
self.fields['second_range'] = forms.CharField(widget=forms.Select(choices=seconds))
else:
self.fields['tutorial'] = forms.CharField(widget=forms.Select(choices=tutorial_choices))
self.fields['minute_range'] = forms.CharField(widget=forms.Select(choices=minutes))
self.fields['second_range'] = forms.CharField(widget=forms.Select(choices=seconds))



class AnswerQuesitionForm(forms.Form):
question = forms.IntegerField(widget=forms.HiddenInput())
body = forms.CharField(widget=forms.Textarea())
Loading