Compare commits

...

26 Commits

Author SHA1 Message Date
Hafiz
872182ce19 Responsive Layout for Equipment Containers
- Added responsive CSS for mobile (<768px) and tablet (769px-1024px)
- Implemented flex-wrap layout that automatically stacks items in rows of 4 on smaller
2025-08-13 12:16:57 -05:00
Hafiz
9a1fb18959 Merge remote-tracking branch 'origin/develop' into qa/bat 2025-08-12 09:46:07 -05:00
Phillip Thelen
2ea0b64603 improve blocker form display 2025-08-05 14:57:25 +02:00
Phillip Thelen
bd1aa1e417 validate blocker value during input 2025-08-05 14:45:23 +02:00
Phillip Thelen
7c49b845d6 add option to errorHandler to skip logging 2025-08-04 17:40:26 +02:00
Phillip Thelen
1ee172139d lint fix 2025-08-04 16:32:40 +02:00
Phillip Thelen
6447b9ab4b update block error strings 2025-08-04 16:03:55 +02:00
Phillip Thelen
5c414099d9 improve navbar display for non fullAccess admin 2025-08-04 14:46:05 +02:00
Phillip Thelen
5e8e1179aa fix managing permissions from admin 2025-08-04 14:45:47 +02:00
Phillip Thelen
7e86a62624 improve permission check 2025-08-04 14:33:09 +02:00
Phillip Thelen
1ba9dda0ed add new permission for managing blockers 2025-08-04 14:21:36 +02:00
Phillip Thelen
227e5ceaa8 fix import 2025-07-30 11:26:55 +02:00
Phillip Thelen
f77ab5a3ab lint fixes 2025-07-30 11:26:55 +02:00
Phillip Thelen
1916faf647 fix 2025-07-30 11:26:55 +02:00
Phillip Thelen
80ecb5cef1 lint fix 2025-07-30 11:26:55 +02:00
Phillip Thelen
75c36e6622 add blocker to block emails from registration 2025-07-30 11:26:55 +02:00
Phillip Thelen
78330c975a Improve blocker UI 2025-07-30 11:26:55 +02:00
Phillip Thelen
95266f6cb3 improve test coverage 2025-07-30 11:26:55 +02:00
Phillip Thelen
e9b2c1b51a restructure admin pages 2025-07-30 11:26:54 +02:00
Phillip Thelen
2a2bea07ab Add UI for managing blockers 2025-07-30 11:26:54 +02:00
Phillip Thelen
ea60ddbf4c Tweak wording 2025-07-30 11:25:51 +02:00
Phillip Thelen
1c2ca0e478 correctly reset local data after creating blocker 2025-07-30 11:25:51 +02:00
Phillip Thelen
ef2b7eb928 Add UI for managing blockers 2025-07-30 11:25:51 +02:00
Phillip Thelen
3d16387a61 add new frontend files 2025-07-30 11:25:41 +02:00
Phillip Thelen
93b7770eaa begin building general blocking solution 2025-07-30 11:25:41 +02:00
Phillip Thelen
a9f84d3307 Read IP blocks from database 2025-07-30 11:25:41 +02:00
8 changed files with 130 additions and 8 deletions

View File

@@ -117,6 +117,15 @@ describe('Blocker middleware', () => {
checkIPBlockedErrorThrown(next);
});
it('throws when the ip is blocked', () => {
req.ip = '192.168.1.1';
sandbox.stub(nconf, 'get').withArgs('BLOCKED_IPS').returns('192.168.1.1');
const attachBlocker = requireAgain(pathToBlocker).default;
attachBlocker(req, res, next);
checkIPBlockedErrorThrown(next);
});
});
describe('Blocking clients', () => {
@@ -194,4 +203,4 @@ describe('Blocker middleware', () => {
expect(calledWith[0] instanceof Forbidden).to.equal(true);
});
});
});
});

View File

@@ -130,4 +130,4 @@ export default {
},
},
};
</script>
</script>

View File

@@ -120,6 +120,7 @@
<div
slot="drawer-slider"
class="equipment items items-one-line"
:class="getContainerClass()"
>
<item
v-for="(label, group) in gearTypesToStrings"
@@ -238,6 +239,86 @@
background: $gray-10 !important;
}
@media (max-width: 768px) {
.equipment.items.items-one-line {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 12px;
padding: 0 8px;
.item-wrapper {
flex: 0 0 auto;
margin-right: 0;
margin-bottom: 8px;
}
&.equipment-scale-default .item-wrapper {
.item {
width: 94px;
height: 92px;
}
.item-label {
width: 94px;
font-size: 12px;
}
}
&.equipment-scale-small .item-wrapper {
.item {
width: 70px;
height: 70px;
}
.item-label {
width: 70px;
font-size: 10px;
}
}
.item-wrapper:nth-child(4n+1) {
clear: left;
}
}
}
@media (min-width: 769px) and (max-width: 1024px) {
.equipment.items.items-one-line {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 12px;
padding: 0 12px;
.item-wrapper {
flex: 0 0 auto;
margin-right: 0;
margin-bottom: 8px;
}
&.equipment-scale-default .item-wrapper {
.item {
width: 84px;
height: 82px;
}
.item-label {
width: 84px;
font-size: 11px;
}
}
&.equipment-scale-small .item-wrapper {
.item {
width: 65px;
height: 65px;
}
.item-label {
width: 65px;
font-size: 10px;
}
}
}
}
</style>
<style lang="scss" scoped>
@@ -351,6 +432,7 @@ export default {
searchText: null,
searchTextThrottled: null,
costumeMode: false,
windowWidth: window.innerWidth,
groupByItems: [
'type', 'class',
],
@@ -523,8 +605,27 @@ export default {
subSection: this.$t('equipment'),
section: this.$t('inventory'),
});
this.handleResize = throttle(() => {
this.windowWidth = window.innerWidth;
}, 250);
window.addEventListener('resize', this.handleResize);
},
beforeDestroy () {
window.removeEventListener('resize', this.handleResize);
},
methods: {
getContainerClass () {
const equippedCount = Object.keys(this.gearTypesToStrings).filter(group => {
const item = this.flatGear[this.activeItems[group]];
return item && item.key.indexOf('_base_0') === -1;
}).length;
if (this.windowWidth <= 1024) {
return equippedCount > 4 ? 'equipment-scale-small' : 'equipment-scale-default';
}
return '';
},
selectDrawerTab (tabName) {
let tabNameValue;
if (tabName === 'costume') {

View File

@@ -111,7 +111,7 @@
.toggle-switch-inner:before {
content: "";
padding-left: 10px;
background-color: $green-50;
background-color: $purple-300;
}
.toggle-switch-inner:after {

View File

@@ -4,4 +4,4 @@
"newsroom": "Newsroom",
"adminBlockerTypeDescription": "<b>IP-Address</b> - Block access for a specific IP-Address\n\nClient - Block access for a client based on the \"x-client\" header.\n\nE-Mail - Blocks e-mails from being used for signup.",
"adminBlockerAreaDescription": "A blocker can either apply to the full site, completely blocking any access. Or it can apply to purchases, which still allows the site to be accessed."
}
}

View File

@@ -187,5 +187,4 @@ api.deleteBlocker = {
res.respond(200, savedBlocker);
},
};
export default api;

View File

@@ -1,3 +1,4 @@
import nconf from 'nconf';
import {
Forbidden,
} from '../libs/errors';
@@ -9,7 +10,19 @@ import { model as Blocker } from '../models/blocker';
// NOTE: it's meant to be used behind a proxy (for example a load balancer)
// that uses the 'x-forwarded-for' header to forward the original IP addresses.
const blockedIps = [];
// A list of comma separated IPs to block
// It works fine as long as the list is short,
// if the list becomes too long for an env variable we'll switch to Redis.
const BLOCKED_IPS_RAW = nconf.get('BLOCKED_IPS');
const blockedIps = BLOCKED_IPS_RAW
? BLOCKED_IPS_RAW
.trim()
.split(',')
.map(blockedIp => blockedIp.trim())
.filter(blockedIp => Boolean(blockedIp))
: [];
const blockedClients = [];
Blocker.watchBlockers({
@@ -53,4 +66,4 @@ export default function ipBlocker (req, res, next) {
}
return next();
}
}