How can I better handle config files? - config

In a package I'm writing, I have a config module that looks like this:
use v6.d;
use JSON::Fast;
use PSBot::Tools;
sub EXPORT(--> Hash) {
my Str $path = do if %*ENV<TESTING> {
$*REPO.Str.IO.child('META6.json').e
?? $*REPO.Str.IO.child('t/config.json').Str # For when testing using zef
!! $*REPO.Str.IO.parent.child('t/config.json').Str; # For when testing using prove
} elsif $*DISTRO.is-win {
"%*ENV<LOCALAPPDATA>\\PSBot\\config.json"
} else {
"$*HOME/.config/PSBot/config.json"
};
unless $path.IO.e {
note "PSBot config at $path does not exist!";
note "Copy psbot.json.example there and read the README for instructions on how to set up the config file.";
exit 1;
}
with from-json slurp $path -> %config {
%(
USERNAME => %config<username>,
PASSWORD => %config<password>,
AVATAR => %config<avatar>,
HOST => %config<host>,
PORT => %config<port>,
SERVERID => %config<serverid>,
COMMAND => %config<command>,
ROOMS => set(%config<rooms>.map: &to-roomid),
ADMINS => set(%config<admins>.map: &to-id),
MAX_RECONNECT_ATTEMPTS => %config<max_reconnect_attempts>,
GIT => %config<git>,
DICTIONARY_API_ID => %config<dictionary_api_id>,
DICTIONARY_API_KEY => %config<dictionary_api_key>,
YOUTUBE_API_KEY => %config<youtube_api_key>,
TRANSLATE_API_KEY => %config<translate_api_key>
)
}
}
Every time I make changes to the config file, I have to delete the precomp files for the changes to appear. Is there a way I can write this so the exports aren't defined at compile time so users don't have to do this?

Assuming I understand your intentions correctly, one way to do it would be this:
get rid of the EXPORT sub
place the computation of $path and %config into the module's mainline
declare your 'constants' as terms such as
sub term:<USERNAME> is export { %config<username> }

After reading you guys' comments and the answer by #Christoph, I settled on this. This does what I want to do:
use v6.d;
use JSON::Fast;
use PSBot::Tools;
unit module PSBot::Config;
my Str $path = do if %*ENV<TESTING> {
%?RESOURCES<test/config.json>.Str
} elsif $*DISTRO.is-win {
Qh[%*ENV<LOCALAPPDATA>\PSBot\config.json]
} else {
"$*HOME/.config/PSBot/config.json"
};
unless $path.IO.e {
note "PSBot config at $path does not exist!";
note "Copy config.json.example there and read the README for instructions on how to set up the config file.";
exit 1;
}
my %config = from-json slurp $path;
sub term:<USERNAME> is export { %config<username> }
sub term:<PASSWORD> is export { %config<password> }
sub term:<AVATAR> is export { %config<avatar> }
sub term:<HOST> is export { %config<host> }
sub term:<PORT> is export { %config<port> }
sub term:<SERVERID> is export { %config<serverid> }
sub term:<COMMAND> is export { %config<command> }
sub term:<ROOMS> is export { set(%config<rooms>.map: &to-roomid) }
sub term:<ADMINS> is export { set(%config<admins>.map: &to-id) }
sub term:<MAX_RECONNECT_ATTEMPTS> is export { %config<max_reconnect_attempts> }
sub term:<GIT> is export { %config<git> }
sub term:<DICTIONARY_API_ID> is export { %config<dictionary_api_id> }
sub term:<DICTIONARY_API_KEY> is export { %config<dictionary_api_key> }
sub term:<YOUTUBE_API_KEY> is export { %config<youtube_api_key> }
sub term:<TRANSLATE_API_KEY> is export { %config<translate_api_key> }

Related

Delete item from pinia state

I am new to vue and I have just started using pinia. I wanna delete an item from array but it does not work
here is my store
import {defineStore} from 'pinia'
export interface ObjectDto {
input: string,
}
interface ObjectDtoInterface {
objects: Array<ObjectDto>
}
export const useSearchHistoryStore = defineStore('objectsStore', {
state: (): ObjectDtoInterface => {
return {
objects: [] as ObjectDto[]
}
},
actions: {
add(dto: ObjectDto) {
if (this.objects
.filter(shd => dto.input === shd.input)
.length === 0) {
this.objects.unshift(dto)
}
},
delete(obj: ObjectDto) {
this.objects = this.objects.filter(e => !(e.input === obj.input))
}
}
})
and here is the function from different .ts file
function delete(obj: ObjectDto) {
objectsStore.delete(obj)
}
add action works perfect, it adds item to the state but when I try to delete an item, nothing happens. The data I pass to delete method is 100% good because I checked this many times
Filter does not mutate the original object, you need to reasing
delete(obj: ObjectDto) {
this.objects = this.objects.filter(e => !(e.input === obj.input))
}
more info https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

Looping over swiper-slides excluding cloned duplicates in cypress

I am new to Cypress and trying to loop the swiper slides excluding cloned duplicates. I am using the index of .each() in cypress but this is not working. Below is my code
if (index != 0 && index >= 22) {
//do something
} else {
//do something
}
Below is the example snapshot of my html code:
Can anyone please suggest the logic to loop only into the original slides?
You can use the :not() pseudo-selector
cy.get('div.swiper-slide:not(.swiper-slide-duplicate)')
.should('have.length', 23) // to show loop is filtered, remove once confirmed
.each($swiperSlide => {
...
or if you prefer to check inside the loop use .not() method
cy.get('div.swiper-slide')
.each($swiperSlide => {
if ($swiperSlide.not(".swiper-slide-duplicate").length) {
} else {
}
})
You can use the jquery hasClass() method with negation to check that the class .swiper-slide-duplicate is not present.
cy.get('div.swiper-slide').each(($ele) => {
if(!$ele.hasClass(".swiper-slide-duplicate")){
//Do something when you don't have the duplicate slide
}
else {
//Do something when you have the duplicate slide
}
})
You can also reverse the check as well, first, you check the presence of the class .swiper-slide-duplicate and then in the else condition you can mention the things when you don't have the duplicate slide.
cy.get('div.swiper-slide').each(($ele) => {
if($ele.hasClass(".swiper-slide-duplicate")){
//Do Something when you have the duplicate slide
}
else {
//Do Something when you don't have the duplicate slide
}
})
You can use the jQuery .attr() method to check if the class is just swiper-slide or has both swiper-slide and swiper-slide-duplicate.
cy.get('div.swiper-slide')
.each($el => {
if($el.attr("class") === "swiper-slide") {
}
else {
}
})
Same approach for data-swiper-slide-index
cy.get('div.swiper-slide')
.each($el => {
if($el.attr("class") === "swiper-slide" && $el.attr("data-swiper-slide-index") !== "0") {
}
else {
}
})
You can use a jQuery .filter() to process each type
cy.get('div.swiper-slide')
.then($els => {
// Process non-duplicates
$els.filter('[class=["swiper-slide"]') // exact match to a single class
.each($el => {
})
// Process duplicates
$els.filter('[class*=["swiper-slide-duplicate"]') // *= means "contains"
.each($el => {
})
})
or in Cypress commands (without jQuery)
// Process non-duplicates
cy.get('div.swiper-slide')
.filter(':not(".swiper-slide-duplicate")')
.each($el => {
...
})
// Process duplicates
cy.get('div.swiper-slide')
.filter('.swiper-slide-duplicate')
.each($el => {
...
})
To loop only into the original slides, use the Cypress .not() command to exclude duplicates.
cy.get('div.swiper-slide')
.not('.swiper-slide-duplicate')
.each($el => {
...
})

Handle paste event in vue2-editor

I'm using this text editor https://github.com/davidroyer/vue2-editor that is based on Quilljs
I want to handle the paste event so it pastes only the plain text without any format but seems in the documentation that paste is not a supported event by default.
Is there any way to add the paste event?
I've already tried using v-on:paste in the Editor and adding the Quill custom module Clipboard but haven't had any success.
As I didn't find a way of doing it with the library I did it with the DOM
onPaste() {
const x = document.getElementById("removePasteFormat");
console.log(x);
x.addEventListener("paste", (e) => {
e.stopPropagation();
e.preventDefault();
let text = e.clipboardData.getData("text/plain");
// access the clipboard using the api
if (document.queryCommandSupported("insertText")) {
document.execCommand("insertText", false, text);
} else {
document.execCommand("paste", false, text);
}
});
},
Added the id to the div containing the text editors like this:
<div id="removePasteFormat"> *<<Here goes the text editor component>>* </div>
And register the method on mounted()
mounted() {
this.onPaste();
},
I think it would be good to make a plugin.
I made it simple.
src/utils/vue2Plugin/clipboard.ts
import Delta from 'quill/node_modules/quill-delta';
import Clipboard from 'quill/modules/clipboard';
import { Quill } from 'vue2-editor';
export class CustomClipboardPlugin extends Clipboard {
public quill!: Quill;
public options: any = {};
constructor(quill: Quill) {
super(quill, {
matchers: [],
});
this.quill = quill;
this.quill.root.addEventListener('paste', this.onPaste.bind(this), true);
}
onPaste(event: ClipboardEvent) {
event.preventDefault();
event.stopPropagation();
const range = this.quill.getSelection(true);
if (range === null) return;
let _textHtml;
if (event.clipboardData?.getData('text/html')) {
_textHtml = event.clipboardData?.getData('text/html');
} else if (event.clipboardData?.getData('text/plain')) {
_textHtml = `<p>${event.clipboardData?.getData('text/plain')}</p>`;
}
if (_textHtml) {
const pastedDelta = this.quill.clipboard.convert(_textHtml);
const delta = new Delta()
.retain(range.index)
.delete(range.length)
.concat(pastedDelta);
this.quill.updateContents(delta, Quill.sources.USER);
this.quill.setSelection(delta.length() - range.length, 0, Quill.sources.SILENT);
}
}
}
vue file
<template>
...
<VueEditor
...
:custom-modules="customModulesForEditor"
...
/>
...
</template>
// script
import CustomClipboardPlugin fro 'src/utils/vue2Plugin/clipboard.ts';
...
data() {
return {
customModulesForEditor: [{ alias: 'clipboard', module: CustomClipboardPlugin }],
};
},
...
I was wondering the same and came up with the following solution.
1 - Use the :editorOptions option referenced here
<template>
VueEditor(:editorOptions="editorSettings")
</template>
2 - Fill with the module.clipboard module with the option described here
3 - You can then handle the paste with your personal function (applied after quill's matcher). I've written mine following this answer on github
<script>
data() {
return {
editorSettings: {
modules: {
clipboard: {
matchers: [[Node.ELEMENT_NODE, this.customQuillClipboardMatcher]]
}
}
}
}
},
methods: {
customQuillClipboardMatcher(node, delta) {
delta.ops = delta.ops.map((op) => {
return {
insert: op.insert
}
})
return delta
},
}
</script>

Laravel /broadcasting/auth Always forbidden with 403 Error

I tried many solutions but no one works for me
I've installed Laravel echo and pusher js and Pusher/Pusher
#bootstrap.js
import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
encrypted: true,
});
#.env
BROADCAST_DRIVER=pusher
PUSHER_APP_ID=my_id
PUSHER_APP_KEY=my_key
PUSHER_APP_SECRET=my_secret
PUSHER_APP_CLUSTER=eu
my event file NewMessage
class NewMessage implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(Message $message)
{
$this->message = $message;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('messages.'. $this->message->to);
}
public function broadcastWith()
{
return ["message" => $this->message];
}
}
channel.php
Broadcast::channel('messages.{id}', function ($user, $id) {
return $user->id === (int) $id;
});
Vue App JS code
mounted(){
Echo.private(`messages${this.user.id}`)
.listen('NewMessage', (e) => {
this.handleIncoming(e.message)
});
},
methods:{
saveNewMessage(msg){
this.messages.push(msg);
},
handleIncoming(message){
if(this.selectedContact && message.from == this.selectedContact.id ){
this.saveNewMessage(message);
return;
}
alert(message.text);
}
}
Api.php
Route::post('/conversation/send', 'Api\ContactController#sendNewMessage');
Contact Controller
public function sendNewMessage(Request $request)
{
$message = Message::create([
'from' => $request->sender_id,
'to' => $request->receiver_id,
'text' => $request->text
]);
broadcast(new NewMessage($message));
return response()->json($message);
}
I also read the official documentation everything is going good but I didn't figure out why, it's a throwing error. Have any idea?
I figure out why it is every time shows auth forbidden or doesn't display auth
Solution:
you need to double-check your PUSHER_APP_KEY because if it is not set correctly, it will through error because our stream not connected with pusher
PUSHER_APP_KEY="PUT KEY HERE"
If you are very sure that your app key is correct then go to the Network tab and click on your pusher app key which like e70ewesdsdssew0
If it is displaying the result like this
{"event":"pusher:connection_established","data":"{\"socket_id\":\"131139.31305364\",\"activity_timeout\":120}"}
your API key is good
if it not correct it will display an error like this
{"event":"pusher:error","data":{"code":4001,"message":"App key 3fdsfdfsdfsd not in this cluster. Did you forget to specify the cluster?"}}
Also, don't forget to put the cluster key
PUSHER_APP_CLUSTER=eu

Puppet. Change any config/text file in most efficient way

I am learning how to use Puppet. An now I am trying to change config file for nscd. I need to change such lines:
server-user nscd
paranoia yes
And let's suppose that full config looks as next:
$ cat /etc/nscd/nscd.conf
logfile /var/log/nscd.log
threads 4
max-threads 32
server-user nobody
stat-user somebody
debug-level 0
reload-count 5
paranoia no
restart-interval 3600
Previously I have wrote such module for replacing needed lines and it looks as follow:
include nscd
class nscd {
define line_replace ($match) {
file_line { $name:
path => '/etc/nscd/nscd.conf',
line => $name,
match => $match,
notify => Service["nscd"]
}
}
anchor{'nscd::begin':}
->
package { 'nscd':
ensure => installed,
}
->
line_replace {
"1" : name => "server-user nscd", match => "^\s*server-user.*$";
"2" : name => "paranoia yes", match => "^\s*paranoia.*$";
}
->
service { 'nscd':
ensure => running,
enable => "true",
}
->
anchor{'nscd::end':}
}
Is it possible to make the same in more efficient way? With arrays or like that?
I recommend you to use the inifile puppet module to easy manage INI-style files like this, but also you can take advantage of the create_resources function:
include nscd
class nscd {
$server_user_line = 'server-user nscd'
$paranoia_line = 'paranoia yes'
$defaults = {
'path' => '/etc/nscd/nscd.conf',
'notify' => Service["nscd"],
}
$lines = {
$server_user_line => {
line => $server_user_line,
match => "^\s*server-user.*$",
},
$paranoia_line => {
line => $paranoia_line,
match => "^\s*paranoia.*$",
}
}
anchor{'nscd::begin':}
->
package { 'nscd':
ensure => installed,
}
->
create_resources(file_line, $lines, $defaults)
->
service { 'nscd':
ensure => running,
enable => "true",
}
->
anchor{'nscd::end':}
}
So I wrote such code:
class nscd($parameters) {
define change_parameters() {
file_line { $name:
path => '/etc/nscd.conf',
line => $name,
# #name.split[0..-2] will remove last element,
# does not matter how many elements in line
match => inline_template('<%="^\\s*"+(#name.split[0..-2]).join("\\s*")+".*$" %>'),
}
}
anchor{'nscd::begin':}
->
package { 'nscd':
ensure => installed,
}
->
change_parameters { $parameters: }
->
service { 'nscd':
ensure => 'running',
enable => true,
hasrestart => true
}
->
anchor{'nscd::end':}
}
And class can be launched by passing list/array to class:
class { 'nscd':
parameters =>
[' server-user nscd',
' paranoia yes',
' enable-cache hosts yes smth',
' shared hosts yes']
}
Then each element from array goes to change_parameters function as $name argument after that inline_template module will generate regexp with ruby one line code.
And the same for each element from list/array.
But anyway I think better to use erb template for such changing.