JITSI video meet - Is there any config or API to kick out all the participants when the host/moderator leaves the meeting? - jitsi

I installed JITSI and created a video meeting platform. I created a meeting and shared it with my friends.
I am the host/moderator of the meeting. My friends who joined the meeting are all participants. Now when I leave/disconnect the meeting, it is not disconnecting for the participants and they are still accessing the meeting room without me(host (or) moderator).
Now, I am searching for a solution to remove the participants when the moderator leaves the meeting.
Thanks in advance.

I used Laravel php framework.
you can assign particular user as moderator. you can use readyToClose api method to pass the redirection url.
in my example, Im passing the meeting end url through the controller. when host end the meeting I used socket to send the signal to all other participants.
<script>
var domain = "meet.example.com";
if(isModerator == true) {
var options = {
userInfo: {
moderator: true,
},
roomName: "123",
width: "100%",
height: "100%",
parentNode: document.querySelector('#container'),
}
} else {
var options = {
userInfo: {
moderator: false,
},
roomName: "123",
width: "100%",
height: "100%",
parentNode: document.querySelector('#container'),
}
}
var api = new JitsiMeetExternalAPI(domain, options);
api.on('readyToClose', () => {
window.location.href = '{{ $meeting_end_url }}';
});
</script>
//pusher
channel.bind('meeting ended', function (meeting) {
window.setTimeout(function() {
window.location.href = '/'; <-- redirect path
}, 5000);
});

The moderator can't kick out participants after leaving the meeting. The first participant who joins the meeting will become the moderator once the actual moderator leaves the meeting.

Use this in button onclick()
endMeetingForAll () {
const { _allParticipant,_changeNotification} = this.props;
_allParticipant.map((participant) => {
if( !participant.local) {
APP.store.dispatch(kickParticipant(participant.id));
}
});
window.APP.conference.hangup(false);
executeCommand('hangup');
window.close();
}
Use the all participant from mapstateToProps return like this:
_allParticipant: getParticipants(state)

Jitsi now includes a feature allowing a moderator to end a conference for all participants: https://github.com/jitsi/jitsi-meet/pull/10838.

Related

How Do I Display Product Images In Shopware 6 Administration

I am working on a Shopware 6 Administrative plugin but displaying product images has been a big headache. I went through shopware repositories of 'product_media', 'media', and generally all folder repositories related to media.
I have not been able to decipher how image linking works since I can not get hold of the exact folder names.
How then do I go about this. Note: I have been able to get correct image names and relevant image data like id, folder id etc.
Below is my module/component idex.js file codes
import template from './images-page.html.twig';
const { Component, Context } = Shopware;
const { Criteria } = Shopware.Data;
Component.register('images', {
template,
inject: ['repositoryFactory', 'mediaService', 'acl'],
metaInfo() {
return {
title: 'images'
};
},
computed: {
/**productMediaRepository() {
return this.repositoryFactory.create(this.product.media.entity);
},*/
productRepository() {
return this.repositoryFactory.create('product');
},
mediaFolderRepository() {
return this.repositoryFactory.create('media_folder');
},
mediaRepository() {
return this.repositoryFactory.create('media');
},
rootFolder() {
const root = this.mediaFolderRepository.create(Context.api);
root.name = this.$tc('sw-media.index.rootFolderName');
root.id = null;
return root;
},
logRep(){
console.log(this.productRepository);
// console.log(this.mediaFolderRepository);
// console.log(this.mediaRepository);
// console.log(this.rootFolder);
}
},
methods: {
logProducts(){
const criteria = new Criteria();
this.productRepository
.search(criteria, Shopware.Context.api)
.then(result => {
console.log(result[0]);
});
},
logMediaFolders(){
const criteria = new Criteria();
this.mediaFolderRepository
.search(criteria, Shopware.Context.api)
.then(result => {
console.log(result);
});
}
},
created(){
this.logMediaFolders();
}
});
here's the twig template (nothing really here)
<sw-card title="Watermark">
<img src="" alt="Product Image" />
</sw-card>
The media elements of the products are associations that are not loaded automatically, but you can configure the criteria, so that those associations will be loaded directly when you fetch the products. Refer to the official docs for detailed infos.
In you case that means to load the cover image / or all product images, you would have to adjust the criteria you use for fetching the products the following way
logProducts(){
const criteria = new Criteria();
criteria.addAssociation('cover.media');
criteria.addAssociation('media.media');
this.productRepository
.search(criteria, Shopware.Context.api)
.then(result => {
console.log(result[0]);
});
},
Then to link to the cover image you can use:
<sw-card title="Watermark">
<img src="product.cover.media.url" alt="Product Image" />
</sw-card>
You find all the media elements of the product as an array under product.media and can also use product.media[0].media.url to link to those images.

Apollo/graphql request result buffered in vuejs

In a Vue component controlling users subsciption to newsletters, I have the fellowing code:
async newSubscriber(event) {
// Validate email
//---------------
if (!this.isEmailValid(this.subscriber_email))
this.subscribeResult = "Email not valid";
else {
// If valid, check if email is not already recorded
//-------------------------------------------------
let alreadyRecorded = false;
let recordedEmails = await this.$apollo.query({ query: gql`query { newslettersEmails { email } }` });
console.log('length ' + recordedEmails.data.newslettersEmails.length);
console.log(recordedEmails.data.newslettersEmails);
for (let i = 0; !alreadyRecorded && i < recordedEmails.data.newslettersEmails.length; i++)
alreadyRecorded = this.subscriber_email === recordedEmails.data.newslettersEmails[i].email;
if (alreadyRecorded)
this.subscribeResult = "Email already recorded";
else {
// If not, record it and warn the user
//------------------------------------
this.$apollo.mutate({
mutation: gql`mutation ($subscriber_email: String!){
createNewslettersEmail(input: { data: { email: $subscriber_email } }) {
newslettersEmail {
email
}
}
}`,
variables: {
subscriber_email: this.subscriber_email,
}
})
.then((data) => { this.subscribeResult = "Email recorded"; })
.catch((error) => { this.subscribeResult = "Error recording the email: " + error.graphQLErrors[0].message; });
}
}
}
At the very first email subscription test, $apollo.query returns me the correct number of emails already recorded (let's say, 10) and record the new subscriber email. But if I try to record a second email without hard refreshing (F5) the browser, $apollo.query returns me the exact same result than the first time (10), EVEN IF the first test email has been correctly recorded by strapi (graphql palyground showns me the added email with the very same query!). Even if I add ten emails, apollo will always return me what it got during its first call (10 recorded emails), as if it uses a buffered result. Of course, that allows Vue to record several times the same email, which I obviously want to avoid!
Does it speaks to anyone ?
After a lot of Google digging (giving the desired results by simply changing in my requests, at the end, "buffering" by "caching" !), I understood that Apollo cache its queries by default (at least, in the configuration of the Vue project I received). To solve the problem I just added "fetchPolicy: 'network-only'" to the query I make:
let recordedEmails = await this.$apollo.query({
query: gql`query { newslettersEmails { email } }`,
});
became
let recordedEmails = await this.$apollo.query({
query: gql`query { newslettersEmails { email } }`,
fetchPolicy: 'network-only'
});
And problem solved ^^

How to save card after payment in stripe?

I want to save a card for next payments in my app, but always get the same exception : "Stripe.StripeException: 'The provided PaymentMethod was previously used with a PaymentIntent without Customer attachment, shared with a connected account without Customer attachment, or was detached from a Customer. It may not be used again. To use a PaymentMethod multiple times, you must attach it to a Customer first.'
"
I don't have any clue, how to solve it.
Here is my Controller.cs:
public class PaymentController : Controller
{
public IActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Processing()
{
var service = new PaymentMethodService();
var obj=service.Get("pm_1ICLE7GcqJgpxMZpnTbfS7Jw");
var paymentIntents = new PaymentIntentService();
var paymentIntent = paymentIntents.Create(new PaymentIntentCreateOptions
{
Amount = 2000,
Currency = "usd",
Customer = "cus_Ing6wBxNYVdB44",
ReceiptEmail = "eman29#jdecorz.com",
PaymentMethod = obj.Id,
Confirm = true,
OffSession = true
});//here exception is thrown
return Json(new { clientSecret = paymentIntent.ClientSecret });
}
}
My client.js code:
var stripe = Stripe("pk_test_51IBEAOGcqJgpxMZpvVKN2j9K7RJpzazfnG4u0relgSXiVBtNDd7nGgxBmX8BNCvuNerv1jnf0UVL5Uz8ODeJ7wvI00ruu2ByVM");
// Disable the button until we have Stripe set up on the page
document.querySelector("button").disabled = true;
fetch("/Payment/Processing", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(purchase)
})
.then(function (result) {
return result.json();
})
.then(function (data) {
var elements = stripe.elements();
var style = {
base: {
color: "#32325d",
fontFamily: 'Arial, sans-serif',
fontSmoothing: "antialiased",
fontSize: "16px",
"::placeholder": {
color: "#32325d"
}
},
invalid: {
fontFamily: 'Arial, sans-serif',
color: "#fa755a",
iconColor: "#fa755a"
}
};
var card = elements.create("card", { style: style });
// Stripe injects an iframe into the DOM
card.mount("#card-element");
card.on("change", function (event) {
// Disable the Pay button if there are no card details in the Element
document.querySelector("button").disabled = event.empty;
document.querySelector("#card-error").textContent = event.error ? event.error.message : "";
});
var form = document.getElementById("payment-form");
form.addEventListener("submit", function (event) {
event.preventDefault();
// Complete payment when the submit button is clicked
payWithCard(stripe, card, data.clientSecret);
});
});
// Calls stripe.confirmCardPayment
// If the card requires authentication Stripe shows a pop-up modal to
// prompt the user to enter authentication details without leaving your page.
var payWithCard = function (stripe, card, clientSecret) {
loading(true);
stripe
.confirmCardPayment(clientSecret, {
payment_method: {
card: card
}
})
.then(function (result) {
if (result.error) {
// Show error to your customer
showError(result.error.message);
} else {
// The payment succeeded!
orderComplete(result.paymentIntent.id);
}
});
};
/* ------- UI helpers ------- */
// Shows a success message when the payment is complete
var orderComplete = function (paymentIntentId) {
loading(false);
document
.querySelector(".result-message a")
.setAttribute(
"href",
"https://dashboard.stripe.com/test/payments/" + paymentIntentId
);
document.querySelector(".result-message").classList.remove("hidden");
document.querySelector("button").disabled = true;
};
// Show the customer the error from Stripe if their card fails to charge
var showError = function (errorMsgText) {
loading(false);
var errorMsg = document.querySelector("#card-error");
errorMsg.textContent = errorMsgText;
setTimeout(function () {
errorMsg.textContent = "";
}, 4000);
};
// Show a spinner on payment submission
var loading = function (isLoading) {
if (isLoading) {
// Disable the button and show a spinner
document.querySelector("button").disabled = true;
document.querySelector("#spinner").classList.remove("hidden");
document.querySelector("#button-text").classList.add("hidden");
} else {
document.querySelector("button").disabled = false;
document.querySelector("#spinner").classList.add("hidden");
document.querySelector("#button-text").classList.remove("hidden");
}
};
I try to use samples from https://stripe.com/docs/payments/save-during-payment and https://stripe.com/docs/payments/save-and-reuse, but can't understand, what I do wrongly
I know this is the dumb question, but it is my first expierence with Stripe and I can't to find any solution for this problem.
Thank you in advance!
When re-using a PaymentMethod for a Customer, it must be attached to them. There is a few ways to go about that. For example, one option is to create a payment method and then to call attach in the backend [1]. The other option is to collect card information using Stripe.js and Elements and to "setup future usage", this will automatically attach the card to the customer [2].
One thing to note, if your code uses confirmCardPayment() [3], that would normally be an "on-session" payment as the user is actively confirming the charge. [4]
[1] https://stripe.com/docs/api/payment_methods/attach
[2] https://stripe.com/docs/js/payment_intents/confirm_card_payment#stripe_confirm_card_payment-data-setup_future_usage
[3] https://stripe.com/docs/js/payment_intents/confirm_card_payment
[4] https://stripe.com/docs/api/payment_intents/create#create_payment_intent-off_session

Finding the number of active push notifications from service worker

I’ve implemented push notifications using service workers. Is there any way to find out the number of notifications which are currently shown in the window? My intention is to limit the number of notifications shown in the window.
I tried the following. But the getNotifications function returning me empty array.
self.addEventListener('push', function(event) {
if (!(self.Notification && self.Notification.permission === 'granted')) {
return;
}
var data = event.data.json();
var options = {
body: data.notificationText,
icon: 'files/assets/staff.png',
vibrate: [100, 50, 100],
data: {
dateOfArrival: Date.now(),
onClickUrl: data.onClickUrl,
event_id: data.event_id,
productName: data.product_name
}
};
event.waitUntil(
self.registration.getNotifications().then(function(notifications) {
console.log(notifications);
if (notifications && notifications.length > 0) {
notifications.forEach(function(notification) {
notification.close();
});
}
showNotification(data.title, options);
})
);
});
You can use serviceWorker.getNotifications() which returns a list of notifications. You can use it like so:
navigator.serviceWorker.register('sw.js');
navigator.serviceWorker.ready.then(function(registration) {
registration.getNotifications().then(function(notifications) {
// get the number of notifications
})
});
if you're doing this in your serviceworker file, it's:
self.registration.getNotifications().then(function(notifications) {
// get the number of notifications
})

Firebase make user object from auth data

So I'm using Angularfire in an ionic app and trying to figure out how to make a user object that is associated with the auth data from an Auth $createUser call. My first try had the auth call and the user got authenticated, then a user object was made and pushed into a $firebaseArray which works fine, but I don't know how to grab the current user after they are logged in to update, destory, or do anything with that users data. I have made it work with looping through the users array and matching the uid from the user array item and the auth.uid item which was set to be the same in the user array object creation. This seems really ineffecient to loop over if there is a large user array and it needs to be done on multiple pages.
My current attempt is using a different method like so:
angular.module('haulya.main')
.controller('RegisterController', ['Auth', '$scope', 'User', '$ionicPlatform', '$cordovaCamera','CurrentUserService',
function(Auth, $scope, User, $ionicPlatform, $cordovaCamera, CurrentUserService) {
//scope variable for controller
$scope.user = {};
console.log(User);
$scope.createUser = function(isValid) {
var userModel;
$scope.submitted = true;
//messages for successful or failed user creation
$scope.user.message = null;
$scope.user.error = null;
//if form is filled out valid
if(isValid) {
//Create user with email and password firebase Auth method
Auth.$createUser({
email: $scope.user.email,
password: $scope.user.password
})
.then(function(userData) {
userModel = {
uid: userData.uid,
photo: $scope.user.photo || null,
firstName: $scope.user.firstName,
lastName: $scope.user.lastName,
email: $scope.user.email,
cell: $scope.user.cell,
dob: $scope.user.dob.toString(),
city: $scope.user.city,
state: $scope.user.state,
zip: $scope.user.zip
}
// add new user to profiles array
User.create(userModel).then(function(user) {
$scope.sharedUser = User.get(user.path.o[1]);
});
$scope.user.message = "User created for email: " + $scope.user.email;
})
.catch(function(error) {
//set error messages contextually
if(error.code == 'INVALID_EMAIL') {
$scope.user.error = "Invalid Email";
}
else if(error.code == 'EMAIL_TAKEN'){
$scope.user.error = "Email already in use, if you think this is an error contact an administrator";
}
else {
$scope.user.error = "Fill in all required fields";
}
});
}
};
//Get profile pic from camera, or photo library
$scope.getPhoto = function(type) {
$ionicPlatform.ready(function() {
//options for images quality/type/size/dimensions
var options = {
quality: 65,
destinationType: Camera.DestinationType.DATA_URL,
sourceType: Camera.PictureSourceType[type.toUpperCase()],
allowEdit: true,
encodingType: Camera.EncodingType.JPEG,
targetWidth: 100,
targetHeight: 100,
popoverOptions: CameraPopoverOptions,
saveToPhotoAlbum: false
};
//get image function using cordova-plugin-camera
$cordovaCamera.getPicture(options)
.then(function(photo) {
$scope.user.photo = photo;
}, function(err) {
console.log(err);
});
});
};
}]);
And here's the service the controller is using:
angular
.module('haulya.main')
.factory('User', function($firebaseArray) {
var ref = new Firebase('https://haulya.firebaseio.com');
var users = $firebaseArray(ref.child('profiles'));
var User = {
all: users,
create: function(user) {
return users.$add(user);
},
get: function(userId) {
return $firebaseArray(ref.child('profiles').child(userId));
},
delete: function(user) {
return users.$remove(user);
}
};
return User;
});
This also works, but again I don't have a solid reference to the currently logged in users object data from the array. The objects id is only stored on the controllers scope.
I looked through other posts, but they were all using older versions of firebase with deprecated methods.
If you're storing items that have a "natural key", it is best to store them under that key. For users this would be the uid.
So instead of storing them with $add(), store them with child().set().
create: function(user) {
var userRef = users.$ref().child(user.uid);
userRef.set(user);
return $firebaseObject(userRef);
}
You'll note that I'm using non-AngularFire methods child() and set(). AngularFire is built on top of Firebase's regular JavaScript SDK, so they interoperate nicely. The advantage of this is that you can use all the power of the Firebase JavaScript SDK and only use AngularFire for what it's best at: binding things to Angular's $scope.
Storing user data is explained in Firebase's guide for JavaScript. We store them under their uid there too instead of using push(), which is what $add() calls behind the scenes.