When a new user is adding to the users collection the html does'nt re-render although I can see it in the websocket.
websocket message
publication.js:
Meteor.publish('users.name.by-game', function(code) {
check(code, String);
this.autorun(function() {
const game = Game.findOne({ code });
return Meteor.users.find(
{ _id: { $in: (game && game.getPlayersId()) || [] } },
{ fields: { 'services.gitlab.username': 1 } },
);
});
});
subscribe line:
export default createContainer(({ code }) => {
const imagesHandle = Meteor.subscribe('images.all');
const usersHandle = Meteor.subscribe('users.name.by-game', code);
const gameHandle = Meteor.subscribe('games.get-by-code', code);
const loading = !imagesHandle.ready() || !gameHandle.ready() ||
!usersHandle.ready();
const game = Game.findOne();
return { loading, game };
}, GameRouterContainer);
You do not need this.autorun(function() { inside the publish function.
Also, if the problem is about rendering, the code you pasted won't let us help you.
Related
How do I make it so it does not just like the newest post and it will like the post that they clicked the like button on?
code:
postSearch.addEventListener("input", (ev) => {
async function findPosts() {
const postsRef = collection(firestore, "posts")
const q = query(postsRef, orderBy("createdAt"));
const querySnapshot = await getDocs(q);
querySnapshot.forEach((post) => {
// doc.data() is never undefined for query doc snapshots
if (post.data().likes == undefined) {
post.data().likes = 0
}
function epicTest() {
let postData = {
description: post.data().description,
display_name: post.data().display_name,
createdAt: post.data().createdAt,
uid: post.data().uid,
title: post.data().title,
likes: post.data().likes + 1
}
console.log(post.id)
console.log(postData)
setDoc(doc(postsRef, post.id), postData)
console.log("this feature hasn't been added yet")
}
let items = querySnapshot.docs.map(post => {
if (post.data().title.includes(ev.target.value) || post.data().description.includes(ev.target.value)) {
return `<div id="postBox">
<h4 id="postName">${post.data().display_name}</h4>
<h1 id="postTitle">${post.data().title}</h1>
<h3 id="postDescription">${post.data().description}</h3>
<div id="likeContainer"><ion-icon name="thumbs-up-outline" id="likeBtn" onclick="epicTest()"></ion-icon><h3 id="likeCount">${post.data().likes}</h3></div>
</div>`
}
});
items.reverse()
postList.innerHTML = items.join('');
if (postList.innerText == "") {
postList.innerText = "no results found"
}
let likeBtn = document.querySelectorAll("#likeBtn")
likeBtn.forEach(item => {
item.addEventListener("click", (ev) => {
let postData = {
description: post.data().description,
display_name: post.data().display_name,
createdAt: post.data().createdAt,
uid: post.data().uid,
title: post.data().title,
likes: post.data().likes + 1
}
console.log(post.id)
console.log(postData)
setDoc(doc(postsRef, post.id), postData)
console.log("this feature hasn't been added yet")
})
})
});
}
findPosts()
})
The following example shows how you can use the function to run whenever a 'Like' button is clicked, check the below sample:
var postRef = new Firebase(firebaseURL + id);
postRef.child('like-count').once('value', function(snapshot) {
var currentLikes = snapshot.val() ? snapshot.val() : 0;
postRef.update({
'postID': id,
'like-count': currentLikes + 1
}, function(error) {
if (error) {
console.log('Data could not be saved:' + error);
} else {
console.log('Data saved successfully');
}
});
getLikeCount(id);
});
}
The basic idea behind this is to pass the post id as a parameter to the function that is called when clicking the like button.
Also check the following examples for similar implementations:
Like/Dislike function for Firebase
Creating like button using firestore and useeffect
Like-Dislike system using Firebase Database
How to implement like button concept
Like button functionality
I'm a new programmer and very new to firebase and I'm trying to get the current user files info to display on the screen, it seems that my problem is that I can get the URL and the metadata separately, how do I combine them? how can I take everything at once?
I need to show the file name, date, time, link to download.
const getUserFiles = async () => {
if (!userUID) {
return null;
}
let listRef = storageRef.child(userUID);
listRef.listAll().then(res => {
// res.prefixes.forEach((item) => {
// });
res.items.forEach(item => {
item.getMetadata().then(item => {
var file = {
name: item.name.toString(),
timeCreated: item.timeCreated.toString(),
link: '',
};
myFiles.push(file);
});
});
res.items.forEach(item => {
let counter = 0;
item.getDownloadURL().then(url => {
myFiles[counter].link = url.toString();
});
});
});
console.log(myFiles);
};
the current method don't work! and notice that the userUID its only the uid without the user (local state)
Thanks!
The problem is with the asynchronous calls. You're making an async call in forEach and forEach expects a synchronous function.
You can change the logic to use for-of instead.
See below:
const getUserFiles = async () => {
if (!userUID) {
return null;
}
let listRef = storageRef.child(userUID);
const res = await listRef.listAll();
for (const itemRef of res.items) {
const itemMetadata = await itemRef.getMetadata();
const url = await itemRef.getDownloadUrl();
var file = {
name: itemMetadata.name.toString(),
timeCreated: itemMetadata.timeCreated.toString(),
link: url,
};
myFiles.push(file);
}
console.log(myFiles);
}
I am working with websockets on nuxt.js proyect, and i need to keep the connection opened and unique (singleton), but i could not achieve it.
I created a custom plugin where i listen for ws events, and openned the connection (checking if it doesnt exists yet -but sometimes it creates several ws instances-), and im calling this plugin from a middleware, which is using in several layouts.
The problem is:
Sometimes the connection does not establish (on page reload i.e.). How can i make sure it always starts on user login and keep openned till logout?
How do i keep just one instance of my plugin?
This is the plugin file i wrote:
export default ({ store, $axios, app }, inject) => {
class EasyWebsocket {
roomNotifications = ''
isOpen() {
return this.roomNotifications && this.roomNotifications.readyState === 1
}
initRoomNotifications(token) {
// if already open do nothing
if (this.isOpen()) {
return
}
console.log('inicializando notifications websocket')
this.roomNotifications = new WebSocket(
`wss://api/ws/chat/?t=${token}`
)
const self = this
this.roomNotifications.onmessage = async function(event) {
// CAPTURING THE WEBSOCKET NOTIFICATION
const { data } = event
const { event_type, room } = JSON.parse(data)
// TODO FRANCO: VER EL CONTADOR DE UNREADMESSAGES
const count = store.state.dashboard.chat.unreadMessagesCount + 1
store.commit('dashboard/chat/SET_UNREAD_MESSAGES_COUNT', count)
switch (event_type) {
case 'ROOM_UPDATED':
console.log('new message', room) // no borrar
await self.newRoomNotification(room)
break
case 'NEW_INVITATION':
console.log('created room', room) // no borrar
await self.newInvitation(room)
break
case 'NEW_MESSAGES':
console.log('new messages room', room) // no borrar
await self.newRoomNotification(room)
if (
store.getters['dashboard/chat/isActive']({ conversation: room })
)
store.commit('dashboard/chat/ADD_MESSAGE', room.last_message)
break
default:
break
}
}
this.roomNotifications.onopen = function(event) {
console.log('opening NOTIFICATION WEBSOCKET --------------', event) // no borrar
}
this.roomNotifications.onclose = function(event) {
}
this.roomNotifications.onerror = function(event) {
}
}
newInvitation(room) {
const invitations = store.getters['dashboard/chat/invitations']
const newInvitations = [room, ...invitations]
store.commit('dashboard/chat/SET_INVITATIONS', newInvitations)
}
async newRoomNotification(room) {
const { name } = room
// GET ALL CONVERSATIONS
const conversations = store.getters['dashboard/chat/visibleConversations']
// FIND CONVERSATION INDEX
const conversationIndex = conversations.findIndex(
(conv) => conv.name === name
)
const newConversations = [...conversations]
if (conversationIndex === -1) {
const conversation = await $axios.$get(
`v2/chat/rooms/${name}/?archived=false`
)
newConversations.unshift(conversation)
} else {
newConversations[conversationIndex] = {
...newConversations[conversationIndex],
...room
}
}
store.commit('dashboard/chat/SET_CONVERSATIONS', newConversations)
}
}
inject('easyWebsocket', EasyWebsocket)
}
Then in the middleware file:
export default async function({ store, $auth, $easyWebsocket }) {
if (!$auth.$state.loggedIn) return
// calling just on client side (websocket doesnt work on ss)
if (process.client) {
$easyWebsocket.prototype.initRoomNotifications(
//userdata
)
}
try {
await store.dispatch('dashboard/chat/getUnreadMessagesCount')
} catch (error) {}
}
I currently use The Twilio Node Helper Library to do various API calls whether it may be to create assistants/services, list them, remove them and various other things when it comes to uploading tasks, samples, fields to create a chatbot on Twilio Autopilot.
An example of one some of these functions include:
async function createAssistant(name, client){
var assistantUid = ""
await client.autopilot.assistants
.create({
friendlyName: name,
uniqueName: name
})
.then(assistant => assistantUid = assistant.sid);
return assistantUid
}
async function getAccount(client){
var valid = true
try {
await client.api.accounts.list()
} catch (e) {
valid = false
}
return valid
}
async function connectToTwilio(twilioAccountSid, twilioAuthToken) {
try{
var client = twilio(twilioAccountSid, twilioAuthToken);
} catch (e){
throw new TwilioRequestError(e)
}
var valid = await getAccount(client)
if(valid && client._httpClient.lastResponse.statusCode === 200){
return client
} else{
throw new Error("Invalid Twilio Credentials")
}
}
where client is the client object returned from require("twilio")(twilioAccountSid, twilioAuthToken).
I was wondering what would the best way of mocking this API to allow me to emulate creating assistants, returning their uniqueNames etc..
I was wondering that I may just define some class like
class TwilioTestClient{
constructor(sid, token){
this.sid = sid
this.token = token
this.assistants = TwilioAssistant()
this.services = TwilioServices()
}
}
Where TwilioAssitant and TwilioServices will be additional classes.
Any help would be greatly appreciated!
I struggled with mocking Twilio for a long time. In fact I previously architected my application such that I could mock a wrapper around the Twilio Node Helper just to avoid mocking the actual library. But recent changes to the architecture meant that was no longer an option. This morning I finally got a mock of the Twilio Node Helper Library working. I'm not familiar with the portions of the Twilio library you are using, but I'm hopeful the example here will help you.
We have a function to check if a phone number is mobile, call it isMobile.js.
const Twilio = require("twilio");
const isMobile = async (num) => {
const TwilioClient = new Twilio(process.env.TWILIO_SID, process.env.TWILIO_AUTH_TOKEN);
try {
const twilioResponse = await TwilioClient.lookups.v1
.phoneNumbers(num)
.fetch({ type: "carrier", mobile_country_code: "carrier" });
const { carrier: { type } = {} } = twilioResponse;
return type === "mobile";
} catch (e) {
return false;
}
};
module.exports = isMobile;
Then build a mock for Twilio in __mocks__/twilio.js
const mockLookupClient = {
v1: { phoneNumbers: () => ({ fetch: jest.fn(() => {}) }) }
};
module.exports = class Twilio {
constructor(sid, token) {
this.lookups = mockLookupClient;
}
};
In the test file isMobile.test.js
jest.mock("twilio");
const Twilio = require("twilio");
const isMobile = require("./isMobile");
const mockFetch = jest.fn();
const mockPhoneNumbers = jest.fn(() => ({
fetch: mockFetch
}));
describe("isMobile", () => {
const TwilioClient = new Twilio(process.env.TWILIO_SID, process.env.TWILIO_AUTH_TOKEN);
const lookupClient = TwilioClient.lookups.v1;
lookupClient.phoneNumbers = mockPhoneNumbers;
beforeEach(() => {
mockFetch.mockReset();
});
test("is a function", () => {
expect(typeof isMobile).toBe("function");
});
test("returns true for valid mobile number", async () => {
const validMobile = "+14037007492";
mockFetch.mockReturnValueOnce({
carrier: { type: "mobile", mobile_country_code: 302 }, // eslint-disable-line camelcase
phoneNumber: validMobile
});
expect(await isMobile(validMobile)).toBe(true);
});
test("returns false for non-mobile number", async () => {
const invalidMobile = "+14035470770";
mockFetch.mockReturnValueOnce({
carrier: { type: "not-mobile", mobile_country_code: null }, // eslint-disable-line camelcase
phoneNumber: invalidMobile
});
expect(await isMobile(invalidMobile)).toBe(false);
});
});
I am trying to get the new wit.ai Bot Engine connected to hubot with Javascript.
Unfortunately I am not a JS Developer so I'm struggling.
Here's the code I have:
'use strict';
const Wit = require('../../../node-wit').Wit;
const firstEntityValue = (entities, entity) => {
const val = entities && entities[entity] &&
Array.isArray(entities[entity]) &&
entities[entity].length > 0 &&
entities[entity][0].value
;
if (!val) {
return null;
}
return typeof val === 'object' ? val.value : val;
};
const actions = {
say: (sessionId, msg, cb) => {
console.log(msg);
cb();
},
merge: (context, entities, cb) => {
const loc = firstEntityValue(entities, "location");
if (loc) context.loc = loc;
cb(context);
},
error: (sessionId, msg) => {
console.log('Oops, I don\'t know what to do.');
},
'fetch-weather': (context, cb) => {
// Here should go the api call, e.g.:
// context.forecast = apiCall(context.loc)
context.forecast = 'sunny';
cb(context);
},
};
const client = new Wit('MY_TOKEN_HERE', actions);
client.interactive();
module.exports = function(robot) {
robot.respond(/hey\s+(.+$)/i, function(msg){
var match = msg.match[1];
msg.send("I've heared: " + match);
console.log(match)
process.stdout.write(match);
});
}
The script listens to "hey botname" and outputs what was written after this. My Problem is I have no clue how to get this input sent to the wit client. Using this script in bash without the hubot stuff works fine towards wit as this is based on the quick start example from wit.ai.
The other issue I'm facing is that I would like to have hubot listen in a private channel with every user and have it respond to every message without prefix. Just as the node example does in the console.
Help is highly apprechiated!
Ok, after fiddling a while I made this work.
Here's what my hubot script looks like now:
'use strict';
const Wit = require('../../../node-wit').Wit;
var room;
const firstEntityValue = (entities, entity) => {
const val = entities && entities[entity] &&
Array.isArray(entities[entity]) &&
entities[entity].length > 0 &&
entities[entity][0].value
;
if (!val) {
return null;
}
return typeof val === 'object' ? val.value : val;
};
const actions = {
say: (sessionId, msg, cb) => {
console.log(msg);
room.send(msg)
cb();
},
merge: (context, entities, cb) => {
const loc = firstEntityValue(entities, "location");
if (loc) context.loc = loc;
cb(context);
},
error: (sessionId, msg) => {
console.log('Oops, I don\'t know what to do.');
room.send('Oops, I don\'t know what to do.')
},
};
const client = new Wit('MY_TOKEN_HERE', actions);
//client.interactive();
module.exports = function(robot) {
robot.listen(function(msg) {
var userID = msg.user.id;
var roomID = msg.user.room;
// is this a direct chat(private room)?
if(roomID.indexOf(userID) >= 0){
if(typeof msg.text == "string"){
client.pxMessage(msg.text);
}
}
return true;
},
function(response){
// save room for replys
room = response;
});
}
additionally I made an awful hack to wit.js to get this work. I added the following function as I was not able to use the available methods to get this working. Basically callbacks and session were holding me back:
this.pxMessage = (message) => {
const sessionId = uuid.v1();
const context = {};
const steps = 5;
this.runActions(
sessionId,
message,
context,
(error, context) => {
if (error) {
l.error(error);
}
rl.prompt();
},
steps
);
}
If someone would take this further and implement it properly I would love to see the result. This hack works and we now have a really smart bot in our rocket.chat who understands natural language and learns every day.
You can directly use this module, it seems to be working well: https://www.npmjs.com/package/hubot-wit
I have just now finished integration. You just need to provide the environment variable WIT_TOKEN and it works beautifully!