Salesforce Apex - ObfuscateUser (invocable for 1 userId from Flow) - salesforce

I've been working on this with no success (I'm a newbie to code). I'm trying to take this code for obfuscateUser and update it for the following:
make it invocable from Salesforce Flow
accept one incoming UserId to obfuscate
Any and all help is greatly appreciated! Thank you!!
Related Documentation: https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_class_System_UserManagement.htm
public class UserManagementController{
public List <User> users {get; set;}
    
    public UserManagementController()
{
        Profile p = [select id from profile where name = 'Customer Community User'];
        
        users = [select username, id from User where profileId=:p.id AND isactive=true];
    }
  //Use method with extreme caution. Data can't be recovered.   
    #InvocableMethod(label='User Management' description='Obfuscate User data and more')
    static public void obfuscate(List<User> users)
    {
        String uid = ApexPages.currentPage().getParameters().get('uid');
        
        if(uid == null)
            return;
        
        User u = [select contactId from user where id=:uid];
            
        System.UserManagement.obfuscateUser(uid);
        
        if(u.contactId != null)
        {
            List <Contact> contacts = [select id from Contact where id=:u.contactId LIMIT 1];
            if (contacts == null || contacts.isEmpty() == true)
return;
                
            delete contacts;
        }
    }
}

The example you've got is for implementing this from a list view I believe. I've updated it below to be a fairly straightforward invocable method. I'm sure you've figured it out by now, but for anyone else looking!
public class UserManagementController {
//Use method with extreme caution. Data can't be recovered.
#InvocableMethod(label='User Management' description='Obfuscate User data and more')
static public void obfuscate(List<Id> ids)
{
for (Id id : ids) {
System.UserManagement.obfuscateUser(id);
}
}

Related

MVVM Messenger Register / Send Message in VB.net

I just need some Help translating from C# to VB.Net in this Case.
I try to learn about MVVM and WPF. I need to communicate between multiple Views. An easy way should be via MvvmLight Messaging.
Unfortunately all Examples I could find are in C# and the Converter does not understand all of the Code.
What I have:
Register A Message
Messenger.Default.Register<GoToPageMessage>( this,( action ) => ReceiveMessage( action ) );
private object ReceiveMessage( GoToPageMessage action )
{
MsgBox( action.PageName );
return null;
}
Which the Converter can not translate.
Send a Message:
Private Function GoToPage2() As Object
Dim msg = New GoToPageMessage() With {
.PageName = "Page2"
}
Messenger.[Default].Send(Of GoToPageMessage)(msg)
Return Nothing
End Function`
The Message Class:
Public Class GoToPageMessage
Public Property PageName As String
End Class
Can Anyone please take a Look at this and maybe translate all to VB.Net?
I understand most of it, but not the action Part. Never heard of this in VB.Net.
Thanks already for all the Help.
The function in VB.NET:
Private Function ReceiveMessage(action As GoToPageMessage) As Object
MsgBox(action.PageName)
Return Nothing
End Function
And the registration:
Messenger.Default.Register(Of GoToPageMessage)(Me, Sub(x) ReceiveMessage(x))

creating a simple back end design in Laravel for private/public ownership

I'm using Laravel for a site where most database objects can be private (i.e., viewed only by their owner) or public (viewed by everyone, including guests). Each of these has a user_id, which I set to NULL when the object is public.
What's the simplest way of authenticating routes for this scenario? For example, in /routes/web.php I have:
Route::get('/{tournament}/players', [TournamentController::class, 'indexPlayers']);
and I want to make sure that tournament->user_id is either NULL or corresponds to the user's id. I was able to do this by explicitly binding tournament in /app/Providers/RouteServiceProvider.php:
Route::bind('tournament', function ($hash) {
$user_id = Auth::user()->id ?? NULL;
return Tournament::where([['hash', $hash], ['user_id', $user_id]])
->orWhere([['hash', $hash], ['user_id', NULL]])
->firstOrFail();
});
but I have the strong feeling that I'm making it too complicated or doing things in the wrong place. Is there a better way? Should I by doing this inside TournamentController, for example?
First, there is now the syntax Auth::id() that can be used as a shorthand for Auth::user()->id ?? NULL, so that saves some trouble.
Next, I ended up moving the logic out of RouteServiceProvider.php and into the controller, so that I can explicitly control what happens for public vs. private objects:
class TournamentController extends Controller
{
public function indexPlayers(Tournament $tournament)
{
if ($tournament->user_id === NULL) {
// public
} else if ($tournament->user_id === Auth::id()) {
// private
} else {
// unauthorized
}
}
...
}

ListDataModel not serializable==won´t run on GAE

Ok so I am really stuck now. I have a h:datatable and the only way to get the row details seems to be DataModel#getRowData(). Unfortunately ListDataModel which is needed to wrap the necessary data is NOT serializable so will not work on GAE, and I really need it to work! Does anyone have any idea about any workaround or some way to make it function.
Help much appreciated!
Mark the property transient (so that it will be skipped during serialization) and introduce lazy loading in the getter.
E.g.
private List<Item> itemList;
private transient DataModel<Item> itemModel;
public DataModel<Item> getItemModel() {
if (itemModel == null) {
itemModel = new ListDataModel<Item>(itemList);
}
return itemModel;
}
There are by the way alternate ways to retrieve the current row. See also How can I pass selected row to commandLink inside dataTable?

Using stored procedures (Linq-to-SQL, not EF) in WCF RIA - Silverlight 4

For the love of heaven and earth I really wish someone could help me out with this issue. It seems everyone has something to say about EF but nothing about Linq-to-SQL.
I am trying to grab some data from my table via a stored procedure, believe me, that's all.
I added the Linq-to-SQL model (LAMP.dbml)
added the stored procedure (getAffectedParcel) from the server explorer. getAffectedParcel takes 2 strings as parameters
Build the application.
Added a domain service class (LAMPService)
Selected the (LAMPDataContext) as the data context class (normally I would tick generate metadata, but since I am not working with tables it's not enabled for ticking)
Added the following function to the LAMPService.cs:
public IEnumerable < getAffectedParcelResult > GetTheAffectedParcels(String v, String vf)
{
return this.DataContext.getAffectedParcel(v, vf).AsEnumerable();
}
Added the following code to a Silverlight page in an attempt to consume the stored procedure:
LAMPContext db = new LAMPContext();
try
{
var q = db.GetTheAffectedParcels("18606004005", "").Value;
foreach (getAffectedParcelResult GAP in q)
{
MessageBox.Show(GAP.Owner);
}
}
catch (Exception ex)
{
MessageBox.Show (ex.Message.ToString());
}
Build and run application. An error occurs stating:
Object reference not set to an instance of an object.
I have tried ~1000,000 ways to see if this thing would work, but to no avail. Please don't tell me to use Entity Framework, I want to use Linq-to-SQL. Can someone (anyone) help me out here.
//houdini
Calling a stored procedure from the Silverlight client happens in the Async world. Let's consider an example from the AdventureWorks database...
Here's what the Domain Service method looks like. It is calling the EF on a stored procedure in the database called 'BillOfMaterials'.
public IQueryable<BillOfMaterial> GetBillOfMaterials()
{
return this.ObjectContext.BillOfMaterials;
}
Back on the client side, here is the code for setting up the call...
public GetSp()
{
InitializeComponent();
DomainService1 ds1 = new DomainService1();
var lo = ds1.Load(ds1.GetBillOfMaterialsQuery());
lo.Completed += LoCompleted;
}
First, the Domain Service is created, and then it is used to load the results of the stored procedure. In this particular case, the result of this is an instance of 'LoadOperation'. These things are async, so the LoadOperation needs to have a callback for when it is finished. The callback code looks like this...
public ObservableCollection<BillOfMaterial> MyList { get; set; }
void LoCompleted(object sender, EventArgs e)
{
LoadOperation lo = sender as LoadOperation;
if(lo!=null)
{
MyList = new ObservableCollection<BillOfMaterial>();
foreach(BillOfMaterial bi in lo.AllEntities)
{
MyList.Add(bi);
}
dataGrid1.ItemsSource = MyList;
}
}
In this method, the 'sender' is dereferenced into the LoadOperation instance, and then all the goodies from the database can be accessed. In this trivial example, a list is built and passed to DataGrid as the ItemsSource. It's good for understanding, but you would probably do something else in practice.
That should solve your problem. :)
The best advice I can give on Silverlight and RIA is never do ANYTHING on your own until you have tried it in AdventureWorks. You will just waste your time and beat your head against the wall.
Firstly, it seems like your DomainService code is written for Invoke() rather than Query(). You should use Query as it enables you to update data back to the server.
Solution: you should add a [Query] attribute to GetTheAffectedParcels on the domain service.
[Query]
public IQueryable<Parcel>
GetTheAffectedParcels(string ParcelNumber, string LotNumber)
{
// etc.
}
Secondly, RIA Services needs to know which is the primary key on the Parcel class.
Solution: Apply a MetadataType attribute to the Parcel class, which allows you to add metadata to the Parcel class indirectly, since it is generated by Linq2Sql and you couldn't add annotations directly to the ParcelId - it'd get wiped away.
[MetadataType(typeof(ParcelMetadata)]
public partial class Parcel
{
}
public class ParcelMetadata
{
[System.ComponentModel.DataAnnotations.Key]
public int ParcelId {get; set; }
}
Thirdly, modify your client like this. Instead try this on the Silverlight client:
LAMPContext db = new LAMPContext();
try
{
var q = db.GetTheAffectedParcelsQuery("18606004005", "");
db.Load(q, (op) =>
{
if (op.HasError)
{
label1.Text = op.Error.Message;
op.MarkErrorAsHandled();
}
else
{
foreach (var parcel in op.Entities)
{
// your code here
}
}
}
}
catch (Exception ex)
{
label1.Text = op.ex.Message;
}
Much thanks to Chui and Garry who practically kicked me in the right direction :) [thanks guys...ouch]
This is the procedure I finally undertook:
-After adding the data model(LINQ2SQL) and the domain service, I created a partial class [as suggested by Chui] and included the following metadata info therein:
[MetadataTypeAttribute(typeof(getAffectedParcelResult.getAffectedParcelResultMetadata))]
public partial class getAffectedParcelResult
{
internal sealed class getAffectedParcelResultMetadata
{
[Key]
public string PENumber { get; set; }
}
}
Then, Adjusted the Domain Service to include the following:
[Query]
public IQueryable<getAffectedParcelResult> GetTheAffectedParcels(string v, string vf)
{
// IEnumerable<getAffectedParcelResult> ap = this.DataContext.getAffectedParcel(v, vf);
return this.DataContext.getAffectedParcel(v, vf).AsQueryable();
}
Then Build the app, afterwhich the getAffectedParcelResult store procedure appeared in the Data Sources panel. I wanted to access this via code however. Therefore, I accessed it in silverlight [.xaml page] via the following:
LAMPContext db = new LAMPContext();
var q = db.GetTheAffectedParcelsQuery("18606004005", "");
db.Load(q, (op) =>
{
if (op.HasError)
{
MessageBox.Show(op.Error.Message);
op.MarkErrorAsHandled();
}
else
{
foreach (getAffectedParcelResult gap in op.Entities)
{
ownerTextBlock.Text = gap.Owner.ToString();
}
}
},false);
This worked nicely. The thing is, my stored procedure returns a complex type so to speak. As of such, it was not possible to map it to any particular entity.
Oh and by the way this article helped out as well:
http://onmick.com/Home/tabid/154/articleType/ArticleView/articleId/2/Pulling-Data-from-Stored-Procedures-in-WCF-RIA-Services-for-Silverlight.aspx

CollectionViewSource Filtering logic

The design I've come up with for filtering is awkward at best, and buggy at worst. The idea is to have a base class to support a pick list, and let subclasses add on additional filtering logic as needed.
What is particularly confusing to me is how to trigger the view to filter as various filtering criteria change (see _ApplyFiler(), below). Is setting the filter that way appropriate? Where should I unsubscribe / set it to null after it filters?
Cheers,
Berryl
ugly code:
public class SubjectPickerBase<T> : ViewModelBase, ISubjectPicker<T>
where T : class, IAvailableItem, INotifyPropertyChanged, IActivitySubject
{
public CollectionViewSource Subjects { get; private set; }
protected SubjectPickerBase() { }
protected void _Initialize(IEnumerable<T> subjects, string subjectName) {
...
Subjects = new CollectionViewSource { Source = subjects };
_ApplyFilter();
}
protected void _ApplyFilter() {
Subjects.View.Filter += Filter;
}
private bool Filter(object obj)
{
var subject = obj as T;
if (ReferenceEquals(subject, null)) return false;
NotifyPropertyChanged(() => Status);
var isIncludedBySubclass = OnFilter(subject);
var isIncludedByBase = subject.IsAvailable;
return isIncludedByBase & isIncludedBySubclass;
}
/// <summary>Hook to allow implementing subclass to provide it's own filter logic</summary>
protected virtual bool OnFilter(T subject) { return true; }
}
public class ProjectSelectionViewModel : SubjectPickerBase<ProjectViewModel>
{
public ProjectSelectionViewModel(IEnumerable<ProjectViewModel> projects)
{
...
_Initialize(projects, Strings.ActivitySubject__Project);
}
public string DescriptionMatchText {
get { return _descriptionMatchText; }
set {
ApplyPropertyChange<ProjectSelectionViewModel, string>(ref _descriptionMatchText, x => x.DescriptionMatchText, value);
_ApplyFilter();
}
}
private string _descriptionMatchText;
protected override bool OnFilter(ProjectViewModel subject)
{
...
var isDescriptionMatch = subject.IsMatch_Description(DescriptionMatchText);
return isPrefixMatch && isMidfixMatch && isSequenceNumberMatch && isDescriptionMatch;
}
}
There are several pieces to a non-trivial manipulation of the view that I was missing, all having to do with refreshing the CollectionView that is a property of the CollectionViewSource:
Refresh
DeferRefresh
NeedsRefresh
IsRefreshDeferred
The first part of my question was when to set the filter. For my use case, what worked best so far turned out to be registering for the CollectionViewSource.Filter event and then using the View.Refresh method each time a filter is changed. The initial registration of the filter event also triggers the event handler, and many of the msdn samples you see show this as a way of filtering a view, and nothing else. But if your scenario is not trivial & the user can change some filter criteria, you need to use one or more of the above refresh related methods & properties.
The second part of my question had to do with whether you needed to unsubscribe to the filter event, and if so, when. Well, it turns out that you don't need to unsubscribe, but if you do so it effectively clears any filtering of the view. And many of the msdn trivial samples do exactly that to clear the filter, which is certainly the way to go if you want to completely clear any filtering, but for my use case was not what I really wanted. What I wanted was to clear some criteria but not others, and so again using Refresh (at the right time) gave me the desired behavior.
HTH,
Berryl

Resources