Skip to content

Commit

Permalink
Merge pull request #25 from spoo-me/9-feature-add-bot-blocking-for-users
Browse files Browse the repository at this point in the history
Feature Add Bot Blocking for Users
  • Loading branch information
Zingzy authored Oct 7, 2024
2 parents 8c66cec + 2600645 commit 3dc1b3b
Show file tree
Hide file tree
Showing 8 changed files with 229 additions and 23 deletions.
17 changes: 10 additions & 7 deletions blueprints/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ def analytics(short_code):
url_data["short_code"] = short_code
url_data["last-click-browser"] = url_data.get("last-click-browser", None)
url_data["last-click-os"] = url_data.get("last-click-os", None)
url_data["block-bots"] = url_data.get("block-bots", False)
url_data["bots"] = url_data.get("bots", {})

url_data["referrer"] = url_data.get("referrer", {})
Expand Down Expand Up @@ -152,16 +153,17 @@ def analytics(short_code):
if len(url_data["os_name"][i]["ips"]) != 0:
url_data["unique_os_name"][i] = len(url_data["os_name"][i]["ips"])
url_data["os_name"][i] = url_data["os_name"][i]["counts"]
except Exception as e:
pass

if "ips" in url_data:
url_data["total_unique_clicks"] = len(url_data["ips"].keys())
(
url_data["average_daily_clicks"],
url_data["average_weekly_clicks"],
url_data["average_monthly_clicks"],
) = calculate_click_averages(url_data)

except Exception as e:
pass
(
url_data["average_daily_clicks"],
url_data["average_weekly_clicks"],
url_data["average_monthly_clicks"],
) = calculate_click_averages(url_data)

if "ips" in url_data:
del url_data["ips"]
Expand Down Expand Up @@ -287,6 +289,7 @@ def export(short_code, format):
url_data["password"] = url_data.get("password")
url_data["last-click-browser"] = url_data.get("last-click-browser")
url_data["last-click-os"] = url_data.get("last-click-os")
url_data["block-bots"] = url_data.get("block-bots", False)
url_data["bots"] = url_data.get("bots", {})

url_data["referrer"] = url_data.get("referrer", {})
Expand Down
27 changes: 27 additions & 0 deletions blueprints/url_shortener.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def shorten_url():
max_clicks = request.values.get("max-clicks")
alias = request.values.get("alias")
expiration_time = request.values.get("expiration-time")
block_bots = request.values.get("block-bots")

if not url:
if request.headers.get("Accept") == "application/json":
Expand Down Expand Up @@ -140,6 +141,9 @@ def shorten_url():
else:
data["expiration-time"] = expiration_time

if block_bots:
data["block-bots"] = True

data["creation-date"] = datetime.now().strftime("%Y-%m-%d")
data["creation-time"] = datetime.now().strftime("%H:%M:%S")

Expand Down Expand Up @@ -173,6 +177,7 @@ def emoji():
password = request.values.get("password")
max_clicks = request.values.get("max-clicks")
expiration_time = request.values.get("expiration-time")
block_bots = request.values.get("block-bots")

if not url:
return jsonify({"UrlError": "URL is required"}), 400
Expand Down Expand Up @@ -243,6 +248,9 @@ def emoji():
else:
data["expiration-time"] = expiration_time

if block_bots:
data["block-bots"] = True

data["creation-date"] = datetime.now().strftime("%Y-%m-%d")
data["creation-time"] = datetime.now().strftime("%H:%M:%S")

Expand Down Expand Up @@ -302,6 +310,7 @@ def redirect_url(short_code):
"total-clicks": 1,
"ips": 1,
"referrer": 1,
"block-bots": 1,
}

short_code = unquote(short_code)
Expand Down Expand Up @@ -413,10 +422,28 @@ def redirect_url(short_code):
for bot in BOT_USER_AGENTS:
bot_re = re.compile(bot, re.IGNORECASE)
if bot_re.search(user_agent):
if url_data.get("block-bots", False):
return (
jsonify({
"error_code": "403",
"error_message": "Access Denied, Bots not allowed",
"host_url": request.host_url,
}),
403,
)
updates["$inc"][f"bots.{bot}"] = 1
break
else:
if crawler_detect.isCrawler(user_agent):
if url_data.get("block-bots", False):
return (
jsonify({
"error_code": "403",
"error_message": "Access Denied, Bots not allowed",
"host_url": request.host_url,
}),
403,
)
updates["$inc"][f"bots.{crawler_detect.getMatches()}"] = 1

# increment the counter for the short code
Expand Down
129 changes: 128 additions & 1 deletion static/css/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ form {
}


label {
label[for=alias],
label[for=password],
label[for=long-url],
label[for=max-clicks] {
display: block;
margin-bottom: 12px;
color: white;
Expand Down Expand Up @@ -412,6 +415,130 @@ a:hover {
transform: scale(1.1);
}

.checkbox-wrapper-4 * {
box-sizing: border-box;
}

label.cbx {
margin: 10px 0;
}

.checkbox-wrapper-4 .cbx {
-webkit-user-select: none;
user-select: none;
cursor: pointer;
padding: 6px 8px;
border-radius: 6px;
overflow: hidden;
transition: all 0.2s ease;
display: inline-block;
}

.checkbox-wrapper-4 .cbx:not(:last-child) {
margin-right: 6px;
}

.block-bot-label {
color: white;
}

.checkbox-wrapper-4 .cbx span {
float: left;
vertical-align: middle;
transform: translate3d(0, 0, 0);
}

.checkbox-wrapper-4 .cbx span:first-child {
position: relative;
width: 18px;
height: 18px;
border-radius: 4px;
transform: scale(1);
background: rgba(255, 255, 255, 0.05);
border: 2px solid rgba(255, 255, 255, 0.2);
transition: all 0.2s ease;
box-shadow: 0 1px 1px rgba(0, 16, 75, 0.05);
}

.checkbox-wrapper-4 .cbx span:first-child svg {
position: absolute;
top: 3px;
left: 2px;
fill: none;
stroke: #fff;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
stroke-dasharray: 16px;
stroke-dashoffset: 16px;
transition: all 0.3s ease;
transition-delay: 0.1s;
transform: translate3d(0, 0, 0);
}

.checkbox-wrapper-4 .cbx span:last-child {
padding-left: 8px;
line-height: 18px;
}

.checkbox-wrapper-4 .cbx:hover span:first-child {
border-color: rgb(38, 0, 255);
}

.checkbox-wrapper-4 .inp-cbx {
position: absolute;
visibility: hidden;
}

.checkbox-wrapper-4 .inp-cbx:checked+.cbx span:first-child {
background: rgb(38, 0, 255);
border-color: rgb(38, 0, 255);
animation: wave-4 0.4s ease;
}

.checkbox-wrapper-4 .inp-cbx:checked+.cbx span:first-child svg {
stroke-dashoffset: 0;
}

.checkbox-wrapper-4 .inline-svg {
position: absolute;
width: 0;
height: 0;
pointer-events: none;
user-select: none;
}

@media screen and (max-width: 640px) {
.checkbox-wrapper-4 .cbx {
width: 100%;
display: inline-block;
}
}

@-moz-keyframes wave-4 {
50% {
transform: scale(0.9);
}
}

@-webkit-keyframes wave-4 {
50% {
transform: scale(0.9);
}
}

@-o-keyframes wave-4 {
50% {
transform: scale(0.9);
}
}

@keyframes wave-4 {
50% {
transform: scale(0.9);
}
}

@media screen and (max-width: 480px) {
.url-container {
margin-left: 6%;
Expand Down
17 changes: 17 additions & 0 deletions templates/api.html
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,12 @@ <h4>Data</h4>
<td>Maximum number of clicks allowed for the shortened URL.</td>
<td>No</td>
</tr>
<tr>
<td>block-bots</td>
<td>Boolean</td>
<td>Whether to block bots from accessing the shortened URL.</td>
<td>No</td>
</tr>
</tbody>
</table>

Expand Down Expand Up @@ -609,6 +615,11 @@ <h4>Data</h4>
<td>Maximum number of clicks allowed for the shortened URL.</td>
<td>No</td>
</tr>
<tr>
<td>block-bots</td>
<td>Boolean</td>
<td>Whether to block bots from accessing the shortened URL.</td>
<td>No</td>
</tbody>
</table>

Expand Down Expand Up @@ -1283,6 +1294,7 @@ <h3><strong>🧑🏻‍💻 Code Examples</strong></h3>
"average_daily_clicks": 1.0,
"average_monthly_clicks": 0.03,
"average_weekly_clicks": 0.14,
"block-bots": false,
"bots": {
"Googlebot": 1
},
Expand Down Expand Up @@ -1364,6 +1376,11 @@ <h4><strong>📑 Response Analysis</strong></h4>
<td>Float</td>
<td>Average Clicks per week since the link was created.</td>
</tr>
<tr>
<td>block-bots</td>
<td>Bool</td>
<td>Tells whether the Bots are blocked from accessing the Short Link.</td>
</tr>
<tr>
<td>bots</td>
<td>Dict</td>
Expand Down
2 changes: 2 additions & 0 deletions templates/docs/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
<link rel="stylesheet" href="{{ url_for('static', filename='css/header.css') }}?v=2">
<link rel="stylesheet" href="{{ url_for('static', filename='css/mobile-header.css') }}?v=3">

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.fluid.classless.min.css">

</head>

<body>
Expand Down
15 changes: 13 additions & 2 deletions templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
<meta name="moz-appearance" content="#adb1ff">
<meta content="#adb1ff" name="msapplication-TileColor">

<link rel="stylesheet" href="{{ url_for('static', filename='css/index.css') }}?v=6">
<link rel="stylesheet" href="{{ url_for('static', filename='css/index.css') }}?v=7">
<link rel="stylesheet" href="{{ url_for('static', filename='css/base.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/header.css') }}?v=2">
<link rel="stylesheet" href="{{ url_for('static', filename='css/self-promo.css') }}?v=2">
Expand Down Expand Up @@ -139,7 +139,6 @@ <h2 class="modal-header">Contact Us</h2>
</div>
</div>

<!-- <form action="/" method="POST" id="urlForm"> -->
<div class="form-section">
<form action="/" method="POST" onsubmit="return validateURL() && validatePassword();">
<h1>
Expand Down Expand Up @@ -179,6 +178,18 @@ <h1>
<label for="max-clicks">Max Clicks</label>
<input type="number" id="max-clicks" name="max-clicks" placeholder="optional" min="1">
</div>
<div class="checkbox-wrapper-4">
<input class="inp-cbx" id="block-bots" type="checkbox" name="block-bots" />
<label class="cbx" for="block-bots"><span>
<svg width="12px" height="10px">
<use xlink:href="#check-4"></use>
</svg></span><span class="block-bot-label">Block Bots</span></label>
<svg class="inline-svg">
<symbol id="check-4" viewbox="0 0 12 10">
<polyline points="1.5 6 4.5 9 10.5 1"></polyline>
</symbol>
</svg>
</div>
<div id="sub">
<button type="submit">Shorten URL</button>
</div>
Expand Down
3 changes: 3 additions & 0 deletions templates/stats_view.html
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ <h2 class="main-data-heading">General Stats</h2>
{% if json_data["expiry"] %}
<p>Expired &nbsp; <code id="expire">{{ json_data["expired"] }}</code></p>
{% endif %}
{% if json_data["block-bots"] %}
<p>Block Bots &nbsp; <code>{{ json_data["block-bots"] }}</code></p>
{% endif %}
<p>Last Click &nbsp; <code>{{ json_data['last-click']}}</code></p>
<p>Last Click Browser &nbsp; <code>{{ json_data["last-click-browser"] }}</code></p>
<p>Last Click OS &nbsp; <code>{{ json_data["last-click-os"] }}</code></p>
Expand Down
Loading

0 comments on commit 3dc1b3b

Please sign in to comment.