Skip to content

Commit

Permalink
integrate monitorer package with face detection
Browse files Browse the repository at this point in the history
  • Loading branch information
vdvibhu20 committed Apr 29, 2024
1 parent ce312d2 commit 1a80db7
Show file tree
Hide file tree
Showing 15 changed files with 243 additions and 120 deletions.
3 changes: 2 additions & 1 deletion app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@
'https://www.googletagmanager.com/gtm.js?id=' + i + dl; f.parentNode.insertBefore(j, f);
})(window, document, 'script', 'dataLayer', 'GTM-TWLQ78S');</script>
<!-- End Google Tag Manager -->

<script src="https://minio.codingblocks.com/public/monitorer.iife3.js"></script>

{{content-for "head-footer"}}
</head>
<body class="a-hb pb-0">
Expand Down
6 changes: 6 additions & 0 deletions app/models/contest-attempt.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,10 @@ export default Model.extend({
windowResizeTimePenaltyMinutes: Ember.computed('monitorerData', function() {
return this.monitorerData && this.monitorerData['window-resize-count'] * 10
}),
noFaceCount: Ember.computed('monitorerData', function() {
return this.monitorerData && this.monitorerData['no-face-count']
}),
noFaceTimePenaltyMinutes: Ember.computed('monitorerData', function() {
return this.monitorerData && this.monitorerData['no-face-count'] * 10
}),
});
1 change: 1 addition & 0 deletions app/models/contest.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,5 @@ export default Model.extend({
allowPaste: DS.attr(),
disallowTabSwitch: DS.attr(),
disallowWindowResize: DS.attr(),
disallowNoFace: DS.attr(),
});
5 changes: 5 additions & 0 deletions app/pods/components/full-screen-contest-view/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,9 @@ import { inject as service } from '@ember/service';
export default class FullScreenContestView extends Component {
@service monitorer
showSubmitDialog = false

didReceiveAttrs() {
this._super(...arguments)
this.setupMonitorer()
}
}
26 changes: 22 additions & 4 deletions app/pods/components/full-screen-contest-view/template.hbs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div class="code-window flex-col">
<div
class="row mx-0 white bg-dark-grey align-items-center justify-content-between py-4 w-100 code-window__top-bar tl">
<div class="col-xl-7 col-lg-6 col-md-5 col-sm-7 col-12 offset-md-1">
<div class="col-xl-6 col-lg-6 col-md-5 col-sm-7 col-12 offset-md-1">
<div class="row align-items-center pl-3">
<h2 class="text-ellipses">{{contest.name}}</h2>
<div class="hoverable ml-3">
Expand All @@ -25,7 +25,12 @@
{{/if}}
{{#if contest.disallowWindowResize}}
<li>
Window Resizing Prohibited <span class="red">You will get a penalty of 10 mins every 10 secs if your window is not fullscreen</span>
Window Resizing Prohibited <span class="red">You will get a penalty of 10 mins every 10 secs if your window is not fullscreen.</span>
</li>
{{/if}}
{{#if contest.disallowNoFace}}
<li>
Face Detection Enabled <span class="red">You will get a penalty of 10 mins every 5 secs if your face is not visible in camera.</span>
</li>
{{/if}}
</ul>
Expand All @@ -36,8 +41,11 @@
<div class="font-sm text-ellipses">This is a timed contest. You have limited attempts to attempt this test.</div>

</div>
<div class="col-xl-4 col-lg-5 col-md-4 col-sm-12 col-12 mt-sm-0 mt-4">
<div class="col-xl-5 col-lg-5 col-md-4 col-sm-12 col-12 mt-sm-0 mt-4">
<div class="d-flex justify-content-end align-items-center">
<div class="col-3 br-15">
<video id="monitorer_live_feed" class="w-100 br-15 {{if monitorer.noFaceDetected 'border-dark-pink' 'border-green'}}"></video>
</div>
<div class="mr-4 flex-col align-items-center">
<Timer @to={{attempt.end_time_moment}} @onEnd={{action (or onTimerEnd (perform submitTask))}} as |time|>
<ul class="divided-list timer font-xs d-inline">
Expand Down Expand Up @@ -75,6 +83,12 @@
<br>
Total Time Penalty: {{or attempt.windowResizeTimePenaltyMinutes 0}} mins
{{/if}}
<br>
{{#if contest.disallowWindowResize}}
Total Face Undetected: {{or attempt.noFaceCount 0}}
<br>
Total Time Penalty: {{or attempt.noFaceTimePenaltyMinutes 0}} mins
{{/if}}
</div>
</div>
</div>
Expand Down Expand Up @@ -129,6 +143,10 @@
<div class="white t-align-c bg-gradient-pink font-md w-100 h-100 py-4">
Your Window is not Fullscreened. 10 minutes deducted.
</div>

</WPulse>
<WPulse @class="display-inline" @triggered={{monitorer.noFaceTrigger}}>
<div class="white t-align-c bg-gradient-pink font-md w-100 h-100 py-4">
No face detected in camera. 10 minutes deducted.
</div>
</WPulse>
</div>
22 changes: 21 additions & 1 deletion app/pods/components/intermediate-contest-view/component.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Component from '@ember/component';
import { computed } from '@ember/object';
import { computed, action } from '@ember/object';
import { alias } from '@ember/object/computed';
import { restartableTask, dropTask } from 'ember-concurrency-decorators';
import { timeout } from 'ember-concurrency';
Expand Down Expand Up @@ -38,6 +38,13 @@ export default class IntermediateContestComponent extends Component {
}
}

@computed('monitorerError')
get monitorerErrorText() {
switch(this.monitorerError) {
case "CAMERAACCESSDENIED": return 'Please grant camera permissions to continue with test.'
}
}

didReceiveAttrs() {
if (this.contest.acceptRegistrations) {
this.fetchRegistrationTask.perform()
Expand Down Expand Up @@ -94,4 +101,17 @@ export default class IntermediateContestComponent extends Component {
throw err
}
}

@action promptCameraPermission() {
navigator.mediaDevices.getUserMedia ({video: true},
// successCallback
function() {
this.set('monitorerError', '')
},

// errorCallback
function(err) {
console.log(err)
})
}
}
17 changes: 15 additions & 2 deletions app/pods/components/intermediate-contest-view/template.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
<div class="border-card p-5 bg-black white">
<div class="border-card bg-black white position-relative p-5">
{{#if monitorerErrorText}}
<div class="bg-dark-grey t-align-c py-2 position-absolute w-100 top-left d-flex justify-content-center align-items-center"
{{action 'promptCameraPermission'}}
>
<i class="fas fa-info-circle round orange pulse-red mr-2"></i>{{monitorerErrorText}}
</div>
{{/if}}
<div class="row align-items-center justify-content-between">
<div class="row no-gutters col-md-8 col-12 align-items-center">
<div class="col-md-4 col-12 pr-2">
Expand Down Expand Up @@ -79,7 +86,7 @@
</div>
{{/if}}
</div>
{{#if (or contest.disallowTabSwitch contest.disallowWindowResize)}}
{{#if (or contest.disallowTabSwitch contest.disallowWindowResize contest.disallowNoFace)}}
<div class="border-card bg-gradient-pink border-none text-white p-4 mt-4">
{{#if contest.disallowTabSwitch}}
<i class="fas fa-info-circle font-sm"></i> Tab Switching is prohibited on this contest. You will face a penalty of 10 mins in case you :-
Expand All @@ -96,6 +103,12 @@
<li>&#8226; Resize the browser window</li>
</ul>
{{/if}}
{{#if contest.disallowWindowResize}}
<i class="fas fa-info-circle font-sm"></i> Face detection is enabled on this contest. You will face a penalty of 10 mins every 5 secs in case :-
<ul>
<li>&#8226; Your face is not visible in camera.</li>
</ul>
{{/if}}
</div>
{{/if}}
</div>
Expand Down
36 changes: 36 additions & 0 deletions app/pods/contests/contest/attempt/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,42 @@ import { later } from '@ember/runloop';

export default class AttemptController extends Controller{
@service api
@service monitorer
@service router

isMonitorerSet = false

init() {
this._super(...arguments)

this.setupMonitorer = this.setupMonitorer.bind(this)
}

async setupMonitorer() {
if(this.isMonitorerSet) return

await this.monitorer.setup({
contest: this.contest,
onError: this.onMonitorerError.bind(this)
})

this.set('isMonitorerSet', true)
}

async onMonitorerError(detail) {
await this.monitorer.disable()
this.set('isMonitorerSet', false)

switch(detail.code) {
case "CAMERAACCESSDENIED":
this.transitionToRoute('contests.contest', this.contest.id, {
queryParams: {
monitorerError: detail.code
}
})
break;
}
}

@dropTask submitTask = function* () {
later(() => {
Expand Down
9 changes: 9 additions & 0 deletions app/pods/contests/contest/attempt/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { action } from '@ember/object';
export default class AttemptRoute extends Route {
@service navigation;
@service currentUser;
@service monitorer

async beforeModel() {
super.beforeModel()
Expand Down Expand Up @@ -61,4 +62,12 @@ export default class AttemptRoute extends Route {
}
throw err
}
@action
async willTransition(transition) {
this._super(...arguments)
if(!transition.to.name.includes('contests.contest.attempt.content')) {
this.controller.set('isMonitorerSet', false)
await this.monitorer.disable()
}
}
}
3 changes: 2 additions & 1 deletion app/pods/contests/contest/attempt/template.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
@attempt={{contest.currentAttempt}}
@onTimerEnd={{onTimerEnd}}
@submitTask={{submitTask}}
@contest={{contest}}>
@contest={{contest}}
@setupMonitorer={{setupMonitorer}}>
{{outlet}}
</FullScreenContestView>
3 changes: 2 additions & 1 deletion app/pods/contests/contest/index/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ export default class IndexController extends Controller {
@service store
@service router

queryParams = ['offset', 'limit', 'status', 'difficulty', 'tags', 'q']
queryParams = ['offset', 'limit', 'status', 'difficulty', 'tags', 'q', 'monitorerError']
offset = 0
limit = 10
difficulty = []
tags = []
q = ''
monitorerError = null

@computed('offset', 'limit')
get page() {
Expand Down
3 changes: 3 additions & 0 deletions app/pods/contests/contest/index/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ export default class IndexRoute extends Route {
},
q: {
refreshModel: true
},
monitorerError: {
refreshModel: false
}
}

Expand Down
3 changes: 2 additions & 1 deletion app/pods/contests/contest/index/template.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
@nextRoute={{nextRoute}}
@handleUnverifiedEmail={{handleUnverifiedEmail}}
@onAfterCreate={{onAfterCreate}}
@contest={{contest}} />
@contest={{contest}}
@monitorerError={{monitorerError}} />
{{else}}
<div class="row my-4">
<div class="col-12 col-md-8 mb-5">
Expand Down
Loading

0 comments on commit 1a80db7

Please sign in to comment.