Synchronisation of Owncloud 8.1 with Lightning - thunderbird

Since the migration to Owncloud 8.1 I'm not able to access shared calendar in Lightning.
Real calendar is available, but "shared with me calendar" not !
Here is a quick and dirty hack to solve this. Just modify :
3rdparty/sabre/dav/lib/DAVACL/Plugin.php
Search for the checkPrivileges function, and replace the if in the foreach by this one :
foreach($privileges as $priv) {
if (!in_array($priv, $acl) and $priv != '{DAV:}read') {
$failed[] = $priv;
}
}
And it's working again !

Related

What is a correct way to obtain FOnlineSubsystemSteam instance in c++ code

I'm trying to get steam app id and steam user id in my Unreal Engine 4 project in the following way:
if (SteamAPI_Init())
{
IOnlineSubsystem* ossBase = IOnlineSubsystem::Get();
FOnlineSubsystemSteam* oss = Cast<FOnlineSubsystemSteam*>(ossBase);
if (!oss) {
printText(TEXT("Steam Subsystem is down!"), FColor::Red.WithAlpha(255));
return;
}
auto SteamID = FString(std::to_string(SteamUser()->GetSteamID().ConvertToUint64()).c_str());
auto AppID = FString(std::to_string(oss->GetSteamAppId()).c_str());
But it is not possible to convert IOnlineSubsystem to FOnlineSubsystemSteam. So what is a correct way to obtain the instance of FOnlineSubsystemSteam?
The solution is to use static_cast:
FOnlineSubsystemSteam* oss = static_cast<FOnlineSubsystemSteam*>(ossBase);
This one works. It seems obvious to use UE4 Cast, but in this case it does not work.

How can I replicate New-SmbGlobalMapping in C# code?

I am writing a service which controls docker containers. I want to have the mounted volume as an Azure share, and thus need to use the SMB Global Mapping. If I use the usual WNetAddConnection2A then I can mount the share just fine in my code, but the containers cannot see it as it is not "global". I can't find source for the PowerShell New-SmbGlobalMapping command (is there a way to see it?) and I can't find a suitable API to call. I hope someone knows the magic incantation I can put in my .NET code.
I can't find source for the PowerShell New-SmbGlobalMapping command
(is there a way to see it?) and I can't find a suitable API to call. I
hope someone knows the magic incantation I can put in my .NET code.
PowerShell uses WMI
In your case, it calls
Create method of the MSFT_SmbMapping class (MSFT_SmbGlobalMapping exactly)
You can use WMI Code Creator to generate/test C# code
EDIT : Test with PowerShell.Create
Test as Admin ("requireAdministrator" in manifest) on Windows 10
Test code (C#, VS 2015) =>
// PowerShell calls CredUIPromptForCredentialsW to display the User/Password dialog (you can call it with P/Invoke if needed)
string sUser = "user#provider.com";
string sPassword = "myPassword";
System.Net.NetworkCredential networkCredential = new System.Net.NetworkCredential(sUser, sPassword, null);
System.Security.SecureString securePassword = new System.Security.SecureString();
foreach (var c in networkCredential.Password)
securePassword.AppendChar(c);
// Add reference to :
// C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0\System.Management.Automation.dll
// Add :
// using System.Management.Automation;
PSCredential psCredential = new PSCredential(networkCredential.UserName, securePassword);
// Error handling must be improved : if I pass an invalid syntax for "RemotePath" or not launched as Admin,
// nothing happens (no error, no result) (on Windows 10)
string sLocalPath = "Q:";
string sRemotePath = "\\\\DESKTOP-EOPIFM5\\Windows 7";
using (var ps = PowerShell.Create())
{
ps.AddCommand("New-SmbGlobalMapping");
ps.AddParameter("LocalPath", sLocalPath);
ps.AddParameter("RemotePath", sRemotePath);
ps.AddParameter("Credential", psCredential);
//ps.AddParameter("RequireIntegrity", false);
//ps.AddParameter("RequirePrivacy", false);
try
{
System.Collections.ObjectModel.Collection<PSObject> collectionResults = ps.Invoke();
foreach (PSObject psObl in collectionResults)
{
Console.WriteLine("Status : {0}", psObl.Members["Status"].Value.ToString());
Console.WriteLine("Local Path : {0}", psObl.Members["LocalPath"].Value.ToString());
Console.WriteLine("Remote Path : {0}\n", psObl.Members["RemotePath"].Value.ToString());
}
}
catch (ParameterBindingException pbe)
{
System.Console.WriteLine("\rNew-SmbGlobalMapping error : {0}: {1}",
pbe.GetType().FullName, pbe.Message);
}
}
// To get and remove the test mapping in PowerShell :
// Get-SmbGlobalMapping
// Remove-SmbGlobalMapping -RemotePath "\\DESKTOP-EOPIFM5\Windows 7" -Force

Setting StrongAuthenticationUserDetails PhoneNumber for AzureAD via Powershell?

That title really flows.
When setting up computers for use with Azure Active Directory, we would have IT do initial setup and config. This included the first sign in and joining to Azure Active Directory. When signing in it forces you to select a verification method. We would use our desk phone or cell phone for ease.
The time has come for us to update that second factor phone number. I know of a way to manually do it via the Azure AD Web UI, but I am looking for a scripted way to set that number in PowerShell.
Here is how I retrieve the number via PowerShell.
Get-msoluser -UserPrincipalName "email#emailaddress.com" | Select-Object -ExpandProperty StrongAuthenticationUserDetails
That code returns this info:
ExtensionData : System.Runtime.Serialization.ExtensionDataObject
AlternativePhoneNumber :
Email :
OldPin :
PhoneNumber : +1 5554445555
Pin :
However, there seems to be no similar option for setting the StrongAuthenticationUserDetails.
All my searches just turned up how to bulk enable 2-factor authentication, which is not what I want to do. I want to leave the StrongAuthentication the same while only updating the phone number.
As I said in comment, it appears there is read-only access for powershell.
There is even opened ticket for that on Azure feedback.
There is a plan to do it, but no ETA. My guess is that you will have to wait if you want to use powershell only.
As workaround, you could use powershell & watir for .NET OR Watin with Watin recorder to automatize it via Internet Explorer. As I don't have a testing Azure; I can not create workable code for you.
Using Watin and powershell - you could check: https://cmille19.wordpress.com/2009/09/01/internet-explorer-automation-with-watin/
The following text and code, I wanted to backup it here, was taken from the above page (all credits to the author):
Next click the record button and click the HTML element you want to
automate. Then stop the WatIN recorder and click copy code to
clipboard icon. This will produce some C# code that just needs to be
translated into PowerShell:
// Windows
WatiN.Core.IE window = new WatiN.Core.IE();
// Frames
Frame frame_sd_scoreboard = window.Frame(Find.ByName("sd") && Find.ByName("scoreboard"));
// Model
Element __imgBtn0_button = frame_sd_scoreboard.Element(Find.ByName("imgBtn0_button"));
// Code
__imgBtn0_button.Click();
window.Dispose();
So, I now know the name of the button and that it is 3 frames deep. A
little WatIN object exploration later, I came up with the follow
script, which clicks a button every 50 mintues.
#Requires -version 2.0
#powershell.exe -STA
[Reflection.Assembly]::LoadFrom( "$ProfileDirLibrariesWatiN.Core.dll" ) | out-null
$ie = new-object WatiN.Core.IE("https://sd.acme.com/CAisd/pdmweb.exe")
$scoreboard = $ie.frames | foreach {$_.frames } | where {$_.name –eq ‘sd’} | foreach {$_.frames } | where {$_.name –eq ‘scoreboard’}
$button = $scoreboard.Element("imgBtn0_button")
while ($true)
{
$button.Click()
#Sleep for 50 minutes
[System.Threading.Thread]::Sleep(3000000)
}
Disclaimer: the code is provided as-is. It might happen that it'll stop working in case MS changes Azure Portal interface.
I'm using the following Greasemonkey script to update alternate email and phone (phone can be updated via Graph API now so the script will be useful for email only):
// ==UserScript==
// #name Unnamed Script 548177
// #version 1
// #grant none
// #namespace https://portal.azure.com
// ==/UserScript==
(function(){
document.addEventListener('keydown', function(e) {
// press alt+shift+g
if (e.keyCode == 71 && e.shiftKey && !e.ctrlKey && e.altKey && !e.metaKey) {
const url = document.URL;
const regex = /https:\/\/portal.azure.com\/#blade\/Microsoft_AAD_IAM\/UserDetailsMenuBlade\/UserAuthMethods\/userId\/[\w-]+\/adminUnitObjectId[\/]*\?\w+=(\d{9})&\w+=([\w\.-#]+)/;
const params = url.match(regex);
const allAuthRows = document.getElementsByClassName('ext-userauthenticationmethods-section-row');
const authRowsArray = Array.from(allAuthRows);
let emailRow;
let phoneRow;
let i;
for (i =0; i < authRowsArray.length; i++) {
if (authRowsArray[i].childNodes[1].childNodes[1].childNodes[0].data === 'Email') {
emailRow = authRowsArray[i]
}
if (authRowsArray[i].childNodes[1].childNodes[1].childNodes.length > 1) {
if (authRowsArray[i].childNodes[1].childNodes[1].childNodes[1].childNodes[0].data === 'Phone') {
phoneRow = authRowsArray[i]
}
}
}
const emailInput = emailRow.childNodes[3].childNodes[1].childNodes[1].childNodes[0].childNodes[0].childNodes[0].childNodes[2];
const phoneInput = phoneRow.childNodes[3].childNodes[1].childNodes[1].childNodes[0].childNodes[0].childNodes[0].childNodes[2];
const event = new Event('input', {
'bubbles': true,
'cancelable': true
});
if (params[1] !== '000000000') {
phoneInput.value = `+48 ${params[1]}`;
phoneInput.dispatchEvent(event);
}
if (params[2] !== 'null') {
emailInput.value = params[2];
emailInput.dispatchEvent(event);
}
setTimeout(() => {
const buttonArr = document.getElementsByClassName('azc-toolbarButton-container fxs-portal-hover');
const saveButton = Array.from(buttonArr).find(e => e.title === 'Save');
saveButton.click();
} , 2000);
}
}, false);
})();
It requires you to open Azure portal with querystring like this (I do it with PowerShell):
https://portal.azure.com/#blade/Microsoft_AAD_IAM/UserDetailsMenuBlade/UserAuthMethods/userId/$($u.ObjectId)/adminUnitObjectId/?param1=$newPhone&param2=$newMail
How to use it:
open only one tab at a time, otherwise you'll receive Unable to sign-in error
from time to time you'll receive that error anyway, so just wait
to trigger the script press Alt+Shift+g after the site is loaded (you can change the shortcut in first if)
once the data is updated and saved, press Ctrl+w to close the current tab and press Alt+Tab to switch to previous window (should be PowerShell)
you're still free to use the code to update the phone. Make sure to change country code (currently +48 for Poland)

Free Shipping Cart rules aren't supported by socolissimoflexibilite (french carrier)

I'm trying to understand why the free shipping cartrule I just created doesn't work on all the available shipping methods.
I have one shipping method that becomes free, and the other (socolissimoflexibilite) doesn't change.
Could someone give me a hint, explanation, or some config/data/code to check on socolissimoflexibilite shipping method?
My first investigations lead me to the sales/quote_address_rate collection: one rate is well changed to 0.00€, but not the other.
I also checked the quote shipping address: its free_shipping field is set to 1.
Ok I found the answer :
We had a module (socolissimoflexibilite) extending the module socolissimosimplicite.
socolissimoflexibilite rewrites the collectRates() function, and freeShipping isn't supported anymore. I had to rewrite this part by myself.
For people getting the same issues with this module, here is the trick :
In Addonline_SoColissimoFlexibilite_Model_Carrier_ShippingMethod class, the collectRates() function must be replaced with this code :
public function collectRates(Mage_Shipping_Model_Rate_Request $request)
{
$rates = parent::collectRates($request);
$shippingAddress = Mage::getSingleton('checkout/session')->getQuote()->getShippingAddress();
if ($shippingAddress && $shippingAddress->getData('soco_product_code') == 'RDV') {
foreach ($rates->getAllRates() as $rate) {
if ($rate->getCarrier()===$this->_code) {
$rate->setPrice($rate->getPrice()+(int)Mage::getStoreConfig('carriers/socolissimoflexibilite/rdv_fees'));
}
}
}
if($shippingAddress->getFreeShipping()) {
foreach ($rates->getAllRates() as $rate) {
if($rate->getCarrier() === $this->_code) {
$rate->setPrice(0) ;
$rate->setCost(0) ;
}
}
}
return $rates;
}
And now, freeShipping rules will be supported by socolissimoflexibilite !

Moodle: Automating user/course creation and enrolments

I had a look at the documentation on enrolments, but all the enrolment methods seem to involve some interaction with the GUI.
Is there a way to script enrolments? Something like:
./moodle_do_enrolments imsdata.xml
Or even some web services calls that I can call from an external program?
I'd like to be able to do the following in an automated fashion:
1) Add a user.
2) Create a course with specified title etc.
3) Enrol that user in that course.
Of course at some point I'd hook this up with our user systems and other management systems, but for the moment, I'm just trying to do a proof of concept.
Where is some documentation that explains the process of automated enrolments?
You could try to create your own PHP script: parse the XML file and use internal moodle functions to solve the problem.
Basic ideas to solve these problems
1) Add a user:
In user/lib.php is a method: user_create_user($user).
Just include that lib.php and find out which information is needed in the user object.
2) Create a course
In course/lib.php is a method: create_course($data, $editoroptions).
Just include that lib.php and find out which information is needed in data array.
3) Enrol a user
I created the following method to do the job for me.
// enroll student to course (roleid = 5 is student role)
function enroll_to_course($courseid, $userid, $roleid=5, $extendbase=3, $extendperiod=0) {
global $DB;
$instance = $DB->get_record('enrol', array('courseid'=>$courseid, 'enrol'=>'manual'), '*', MUST_EXIST);
$course = $DB->get_record('course', array('id'=>$instance->courseid), '*', MUST_EXIST);
$today = time();
$today = make_timestamp(date('Y', $today), date('m', $today), date('d', $today), 0, 0, 0);
if(!$enrol_manual = enrol_get_plugin('manual')) { throw new coding_exception('Can not instantiate enrol_manual'); }
switch($extendbase) {
case 2:
$timestart = $course->startdate;
break;
case 3:
default:
$timestart = $today;
break;
}
if ($extendperiod <= 0) { $timeend = 0; } // extendperiod are seconds
else { $timeend = $timestart + $extendperiod; }
$enrolled = $enrol_manual->enrol_user($instance, $userid, $roleid, $timestart, $timeend);
add_to_log($course->id, 'course', 'enrol', '../enrol/users.php?id='.$course->id, $course->id);
return $enrolled;
}
Using a GUI is not necessary, you can create an enrolment/authentication plugin to achieve this or use one of the built in ones. I'm not too familiar with the ims enrollment plugin, but the standard ldap/database plugins have scripts which can be used to automate this sync process.
See for example:
enrol/database/cli/sync.php