├── .gitignore
├── Doc
└── screenshots
│ └── SandboxBerryScreenshot1.png
├── ExampleInstructionFiles
└── ExampleInstructionFile1.xml
├── License_Gpl2.txt
├── README.md
├── Sandboxberry
├── AboutForm.Designer.cs
├── AboutForm.cs
├── AboutForm.resx
├── App.config
├── Berryicon48.ico
├── MainForm.Designer.cs
├── MainForm.cs
├── MainForm.resx
├── Program.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── Resources
│ ├── Berryicon.png
│ ├── Berryicon48.ico
│ ├── Berryicon48.png
│ └── loader.gif
├── Sandboxberry.csproj
├── logging.config
└── packages.config
├── SandboxberryLib
├── InstructionsModel
│ ├── SbbCredentials.cs
│ ├── SbbFieldOption.cs
│ ├── SbbInstructionSet.cs
│ └── SbbObject.cs
├── ObjectTransformer.cs
├── PopulateSandbox.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── RelationMapper.cs
├── Resources
│ └── SbbInstructionSetSchema.xsd
├── ResultsModel
│ ├── PopulateObjectResult.cs
│ ├── PopulateSandboxResult.cs
│ └── RowFailInfo.cs
├── SalesforceSession.cs
├── SalesforceTasks.cs
├── SalesforceWsdl
│ └── partner.wsdl
├── SandboxberryLib.csproj
├── Web References
│ └── SalesforcePartnerApi
│ │ ├── DeleteResult.datasource
│ │ ├── DescribeAppMenuItem.datasource
│ │ ├── DescribeApprovalLayout.datasource
│ │ ├── DescribeAvailableQuickActionResult.datasource
│ │ ├── DescribeCompactLayout.datasource
│ │ ├── DescribeCompactLayoutsResult.datasource
│ │ ├── DescribeDataCategoryGroupResult.datasource
│ │ ├── DescribeDataCategoryGroupStructureResult.datasource
│ │ ├── DescribeFlexiPageResult.datasource
│ │ ├── DescribeGlobalResult.datasource
│ │ ├── DescribeGlobalTheme.datasource
│ │ ├── DescribeLayoutResult.datasource
│ │ ├── DescribeQuickActionResult.datasource
│ │ ├── DescribeSObjectResult.datasource
│ │ ├── DescribeSearchLayoutResult.datasource
│ │ ├── DescribeSearchScopeOrderResult.datasource
│ │ ├── DescribeSoftphoneLayoutResult.datasource
│ │ ├── DescribeSoqlListView.datasource
│ │ ├── DescribeTab.datasource
│ │ ├── DescribeTabSetResult.datasource
│ │ ├── DescribeThemeItem.datasource
│ │ ├── EmptyRecycleBinResult.datasource
│ │ ├── ExecuteListViewResult.datasource
│ │ ├── GetDeletedResult.datasource
│ │ ├── GetServerTimestampResult.datasource
│ │ ├── GetUpdatedResult.datasource
│ │ ├── GetUserInfoResult.datasource
│ │ ├── InvalidateSessionsResult.datasource
│ │ ├── KnowledgeSettings.datasource
│ │ ├── LeadConvertResult.datasource
│ │ ├── LoginResult.datasource
│ │ ├── MergeResult.datasource
│ │ ├── PerformQuickActionResult.datasource
│ │ ├── ProcessResult.datasource
│ │ ├── QueryResult.datasource
│ │ ├── QuickActionTemplateResult.datasource
│ │ ├── Reference.cs
│ │ ├── Reference.map
│ │ ├── ResetPasswordResult.datasource
│ │ ├── SaveResult.datasource
│ │ ├── SearchResult.datasource
│ │ ├── SendEmailResult.datasource
│ │ ├── SetPasswordResult.datasource
│ │ ├── UndeleteResult.datasource
│ │ ├── UpsertResult.datasource
│ │ ├── partner.wsdl
│ │ └── sObject.datasource
├── app.config
└── packages.config
├── SandboxberryOpenSourceSol.sln
├── SandboxberryTests
├── App.config
├── GeneralTests.cs
├── Properties
│ └── AssemblyInfo.cs
├── SandboxberryTests.csproj
├── TestUtils.cs
├── logging.config
└── packages.config
└── notes.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # Build results
11 | [Dd]ebug/
12 | [Dd]ebugPublic/
13 | [Rr]elease/
14 | [Rr]eleases/
15 | x64/
16 | x86/
17 | build/
18 | bld/
19 | [Bb]in/
20 | [Oo]bj/
21 |
22 | # Roslyn cache directories
23 | *.ide/
24 |
25 | # MSTest test Results
26 | [Tt]est[Rr]esult*/
27 | [Bb]uild[Ll]og.*
28 |
29 | #NUNIT
30 | *.VisualState.xml
31 | TestResult.xml
32 |
33 | # Build Results of an ATL Project
34 | [Dd]ebugPS/
35 | [Rr]eleasePS/
36 | dlldata.c
37 |
38 | *_i.c
39 | *_p.c
40 | *_i.h
41 | *.ilk
42 | *.meta
43 | *.obj
44 | *.pch
45 | *.pdb
46 | *.pgc
47 | *.pgd
48 | *.rsp
49 | *.sbr
50 | *.tlb
51 | *.tli
52 | *.tlh
53 | *.tmp
54 | *.tmp_proj
55 | *.log
56 | *.vspscc
57 | *.vssscc
58 | .builds
59 | *.pidb
60 | *.svclog
61 | *.scc
62 |
63 | # Chutzpah Test files
64 | _Chutzpah*
65 |
66 | # Visual C++ cache files
67 | ipch/
68 | *.aps
69 | *.ncb
70 | *.opensdf
71 | *.sdf
72 | *.cachefile
73 |
74 | # Visual Studio profiler
75 | *.psess
76 | *.vsp
77 | *.vspx
78 |
79 | # TFS 2012 Local Workspace
80 | $tf/
81 |
82 | # Guidance Automation Toolkit
83 | *.gpState
84 |
85 | # ReSharper is a .NET coding add-in
86 | _ReSharper*/
87 | *.[Rr]e[Ss]harper
88 | *.DotSettings.user
89 |
90 | # JustCode is a .NET coding addin-in
91 | .JustCode
92 |
93 | # TeamCity is a build add-in
94 | _TeamCity*
95 |
96 | # DotCover is a Code Coverage Tool
97 | *.dotCover
98 |
99 | # NCrunch
100 | _NCrunch_*
101 | .*crunch*.local.xml
102 |
103 | # MightyMoose
104 | *.mm.*
105 | AutoTest.Net/
106 |
107 | # Web workbench (sass)
108 | .sass-cache/
109 |
110 | # Installshield output folder
111 | [Ee]xpress/
112 |
113 | # DocProject is a documentation generator add-in
114 | DocProject/buildhelp/
115 | DocProject/Help/*.HxT
116 | DocProject/Help/*.HxC
117 | DocProject/Help/*.hhc
118 | DocProject/Help/*.hhk
119 | DocProject/Help/*.hhp
120 | DocProject/Help/Html2
121 | DocProject/Help/html
122 |
123 | # Click-Once directory
124 | publish/
125 |
126 | # Publish Web Output
127 | *.[Pp]ublish.xml
128 | *.azurePubxml
129 | # TODO: Comment the next line if you want to checkin your web deploy settings
130 | # but database connection strings (with potential passwords) will be unencrypted
131 | *.pubxml
132 | *.publishproj
133 |
134 | # NuGet Packages
135 | *.nupkg
136 | # The packages folder can be ignored because of Package Restore
137 | **/packages/*
138 | # except build/, which is used as an MSBuild target.
139 | !**/packages/build/
140 | # If using the old MSBuild-Integrated Package Restore, uncomment this:
141 | #!**/packages/repositories.config
142 |
143 | # Windows Azure Build Output
144 | csx/
145 | *.build.csdef
146 |
147 | # Windows Store app package directory
148 | AppPackages/
149 |
150 | # Others
151 | sql/
152 | *.Cache
153 | ClientBin/
154 | [Ss]tyle[Cc]op.*
155 | ~$*
156 | *~
157 | *.dbmdl
158 | *.dbproj.schemaview
159 | *.pfx
160 | *.publishsettings
161 | node_modules/
162 | bower_components/
163 |
164 | # RIA/Silverlight projects
165 | Generated_Code/
166 |
167 | # Backup & report files from converting an old project file
168 | # to a newer Visual Studio version. Backup files are not needed,
169 | # because we have git ;-)
170 | _UpgradeReport_Files/
171 | Backup*/
172 | UpgradeLog*.XML
173 | UpgradeLog*.htm
174 |
175 | # SQL Server files
176 | *.mdf
177 | *.ldf
178 |
179 | # Business Intelligence projects
180 | *.rdl.data
181 | *.bim.layout
182 | *.bim_*.settings
183 |
184 | # Microsoft Fakes
185 | FakesAssemblies/
186 |
187 | # Subversion
188 | .svn/
--------------------------------------------------------------------------------
/Doc/screenshots/SandboxBerryScreenshot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeulike/SandboxBerry/2d1ed91fba78594b344e5fe57cefb14be89460da/Doc/screenshots/SandboxBerryScreenshot1.png
--------------------------------------------------------------------------------
/ExampleInstructionFiles/ExampleInstructionFile1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/License_Gpl2.txt:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
3 |
4 | 0. This License applies to any program or other work which contains
5 | a notice placed by the copyright holder saying it may be distributed
6 | under the terms of this General Public License. The "Program", below,
7 | refers to any such program or work, and a "work based on the Program"
8 | means either the Program or any derivative work under copyright law:
9 | that is to say, a work containing the Program or a portion of it,
10 | either verbatim or with modifications and/or translated into another
11 | language. (Hereinafter, translation is included without limitation in
12 | the term "modification".) Each licensee is addressed as "you".
13 |
14 | Activities other than copying, distribution and modification are not
15 | covered by this License; they are outside its scope. The act of
16 | running the Program is not restricted, and the output from the Program
17 | is covered only if its contents constitute a work based on the
18 | Program (independent of having been made by running the Program).
19 | Whether that is true depends on what the Program does.
20 |
21 | 1. You may copy and distribute verbatim copies of the Program's
22 | source code as you receive it, in any medium, provided that you
23 | conspicuously and appropriately publish on each copy an appropriate
24 | copyright notice and disclaimer of warranty; keep intact all the
25 | notices that refer to this License and to the absence of any warranty;
26 | and give any other recipients of the Program a copy of this License
27 | along with the Program.
28 |
29 | You may charge a fee for the physical act of transferring a copy, and
30 | you may at your option offer warranty protection in exchange for a fee.
31 |
32 | 2. You may modify your copy or copies of the Program or any portion
33 | of it, thus forming a work based on the Program, and copy and
34 | distribute such modifications or work under the terms of Section 1
35 | above, provided that you also meet all of these conditions:
36 |
37 | a) You must cause the modified files to carry prominent notices
38 | stating that you changed the files and the date of any change.
39 |
40 | b) You must cause any work that you distribute or publish, that in
41 | whole or in part contains or is derived from the Program or any
42 | part thereof, to be licensed as a whole at no charge to all third
43 | parties under the terms of this License.
44 |
45 | c) If the modified program normally reads commands interactively
46 | when run, you must cause it, when started running for such
47 | interactive use in the most ordinary way, to print or display an
48 | announcement including an appropriate copyright notice and a
49 | notice that there is no warranty (or else, saying that you provide
50 | a warranty) and that users may redistribute the program under
51 | these conditions, and telling the user how to view a copy of this
52 | License. (Exception: if the Program itself is interactive but
53 | does not normally print such an announcement, your work based on
54 | the Program is not required to print an announcement.)
55 |
56 | These requirements apply to the modified work as a whole. If
57 | identifiable sections of that work are not derived from the Program,
58 | and can be reasonably considered independent and separate works in
59 | themselves, then this License, and its terms, do not apply to those
60 | sections when you distribute them as separate works. But when you
61 | distribute the same sections as part of a whole which is a work based
62 | on the Program, the distribution of the whole must be on the terms of
63 | this License, whose permissions for other licensees extend to the
64 | entire whole, and thus to each and every part regardless of who wrote it.
65 |
66 | Thus, it is not the intent of this section to claim rights or contest
67 | your rights to work written entirely by you; rather, the intent is to
68 | exercise the right to control the distribution of derivative or
69 | collective works based on the Program.
70 |
71 | In addition, mere aggregation of another work not based on the Program
72 | with the Program (or with a work based on the Program) on a volume of
73 | a storage or distribution medium does not bring the other work under
74 | the scope of this License.
75 |
76 | 3. You may copy and distribute the Program (or a work based on it,
77 | under Section 2) in object code or executable form under the terms of
78 | Sections 1 and 2 above provided that you also do one of the following:
79 |
80 | a) Accompany it with the complete corresponding machine-readable
81 | source code, which must be distributed under the terms of Sections
82 | 1 and 2 above on a medium customarily used for software interchange; or,
83 |
84 | b) Accompany it with a written offer, valid for at least three
85 | years, to give any third party, for a charge no more than your
86 | cost of physically performing source distribution, a complete
87 | machine-readable copy of the corresponding source code, to be
88 | distributed under the terms of Sections 1 and 2 above on a medium
89 | customarily used for software interchange; or,
90 |
91 | c) Accompany it with the information you received as to the offer
92 | to distribute corresponding source code. (This alternative is
93 | allowed only for noncommercial distribution and only if you
94 | received the program in object code or executable form with such
95 | an offer, in accord with Subsection b above.)
96 |
97 | The source code for a work means the preferred form of the work for
98 | making modifications to it. For an executable work, complete source
99 | code means all the source code for all modules it contains, plus any
100 | associated interface definition files, plus the scripts used to
101 | control compilation and installation of the executable. However, as a
102 | special exception, the source code distributed need not include
103 | anything that is normally distributed (in either source or binary
104 | form) with the major components (compiler, kernel, and so on) of the
105 | operating system on which the executable runs, unless that component
106 | itself accompanies the executable.
107 |
108 | If distribution of executable or object code is made by offering
109 | access to copy from a designated place, then offering equivalent
110 | access to copy the source code from the same place counts as
111 | distribution of the source code, even though third parties are not
112 | compelled to copy the source along with the object code.
113 |
114 | 4. You may not copy, modify, sublicense, or distribute the Program
115 | except as expressly provided under this License. Any attempt
116 | otherwise to copy, modify, sublicense or distribute the Program is
117 | void, and will automatically terminate your rights under this License.
118 | However, parties who have received copies, or rights, from you under
119 | this License will not have their licenses terminated so long as such
120 | parties remain in full compliance.
121 |
122 | 5. You are not required to accept this License, since you have not
123 | signed it. However, nothing else grants you permission to modify or
124 | distribute the Program or its derivative works. These actions are
125 | prohibited by law if you do not accept this License. Therefore, by
126 | modifying or distributing the Program (or any work based on the
127 | Program), you indicate your acceptance of this License to do so, and
128 | all its terms and conditions for copying, distributing or modifying
129 | the Program or works based on it.
130 |
131 | 6. Each time you redistribute the Program (or any work based on the
132 | Program), the recipient automatically receives a license from the
133 | original licensor to copy, distribute or modify the Program subject to
134 | these terms and conditions. You may not impose any further
135 | restrictions on the recipients' exercise of the rights granted herein.
136 | You are not responsible for enforcing compliance by third parties to
137 | this License.
138 |
139 | 7. If, as a consequence of a court judgment or allegation of patent
140 | infringement or for any other reason (not limited to patent issues),
141 | conditions are imposed on you (whether by court order, agreement or
142 | otherwise) that contradict the conditions of this License, they do not
143 | excuse you from the conditions of this License. If you cannot
144 | distribute so as to satisfy simultaneously your obligations under this
145 | License and any other pertinent obligations, then as a consequence you
146 | may not distribute the Program at all. For example, if a patent
147 | license would not permit royalty-free redistribution of the Program by
148 | all those who receive copies directly or indirectly through you, then
149 | the only way you could satisfy both it and this License would be to
150 | refrain entirely from distribution of the Program.
151 |
152 | If any portion of this section is held invalid or unenforceable under
153 | any particular circumstance, the balance of the section is intended to
154 | apply and the section as a whole is intended to apply in other
155 | circumstances.
156 |
157 | It is not the purpose of this section to induce you to infringe any
158 | patents or other property right claims or to contest validity of any
159 | such claims; this section has the sole purpose of protecting the
160 | integrity of the free software distribution system, which is
161 | implemented by public license practices. Many people have made
162 | generous contributions to the wide range of software distributed
163 | through that system in reliance on consistent application of that
164 | system; it is up to the author/donor to decide if he or she is willing
165 | to distribute software through any other system and a licensee cannot
166 | impose that choice.
167 |
168 | This section is intended to make thoroughly clear what is believed to
169 | be a consequence of the rest of this License.
170 |
171 | 8. If the distribution and/or use of the Program is restricted in
172 | certain countries either by patents or by copyrighted interfaces, the
173 | original copyright holder who places the Program under this License
174 | may add an explicit geographical distribution limitation excluding
175 | those countries, so that distribution is permitted only in or among
176 | countries not thus excluded. In such case, this License incorporates
177 | the limitation as if written in the body of this License.
178 |
179 | 9. The Free Software Foundation may publish revised and/or new versions
180 | of the General Public License from time to time. Such new versions will
181 | be similar in spirit to the present version, but may differ in detail to
182 | address new problems or concerns.
183 |
184 | Each version is given a distinguishing version number. If the Program
185 | specifies a version number of this License which applies to it and "any
186 | later version", you have the option of following the terms and conditions
187 | either of that version or of any later version published by the Free
188 | Software Foundation. If the Program does not specify a version number of
189 | this License, you may choose any version ever published by the Free Software
190 | Foundation.
191 |
192 | 10. If you wish to incorporate parts of the Program into other free
193 | programs whose distribution conditions are different, write to the author
194 | to ask for permission. For software which is copyrighted by the Free
195 | Software Foundation, write to the Free Software Foundation; we sometimes
196 | make exceptions for this. Our decision will be guided by the two goals
197 | of preserving the free status of all derivatives of our free software and
198 | of promoting the sharing and reuse of software generally.
199 |
200 | NO WARRANTY
201 |
202 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
203 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
204 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
205 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
206 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
207 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
208 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
209 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
210 | REPAIR OR CORRECTION.
211 |
212 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
213 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
214 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
215 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
216 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
217 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
218 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
219 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
220 | POSSIBILITY OF SUCH DAMAGES.
221 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SandboxBerry
2 | A tool for copying test data into Salesforce sandboxes
3 |
4 | # What is this for?
5 |
6 | During Salesforce development you will generally create Sandboxes based on your production environment, and then
7 | do development in the Sandbox. Most Salesforce Sandboxes are blank (except for the more expensive ones). Generally to do
8 | some development you're going to want some data in there, for example
9 |
10 | * Any reference tables/objects you've created (e.g. Geo_Country__c - a list of countries)
11 | * Some sample data in the main tables to experiment with during development.
12 |
13 | So ... you can try and copy some data accross using DataLoader or an ETL tool, but you'll quickly find:
14 |
15 | * Ids of each row of data change when you transfer it to the Sandbox, which makes things difficult with related data
16 | (e.g. Accounts and Contacts)
17 | * You will sometimes have different fields in your Sandbox (old fields removed, new fields added)
18 | * Users who are owners of records may have been deactivated in production or might be missing from the Sandbox,
19 | making it difficult to transfer their records
20 |
21 | SandboxBerry can help with these problems.
22 |
23 | This is how SandboxBerry works:
24 |
25 | * You give it a list of Salesforce objects (in the form of an XML file)
26 | * optionally you can specify filters for those objects in SOQL syntax
27 | * SandboxBerry will then transfer the data for those objects from your Source (usually Production) to a Target (always a Sandbox)
28 | * While transferring the data, it fixes the following problems:
29 | * Relationships between objects will automatically be preserved, substituting new Ids for the old Ids
30 | * Any inactive or missing users will be defaulted to the user specified by you
31 | * Only the objects fields that are present in both Source and Target will be transferred
32 | * Optionally, you can skip specific fields or hard-code their values in the Target - this can be useful for anonymisation
33 |
34 | Please note that SandboxBerry takes some liberties with the data to get it to fit into your sandbox (e.g. changing the owner
35 | of records). The idea is: Its test data, so its better to have something rather than nothing. However this means that SandboxBerry
36 | should not be used for transferring **into** a production instance. Because of this, SandboxBerry will only allow you to specify Sandboxes
37 | as the target.
38 |
39 | # License
40 |
41 | SandboxBerry is Open Source under the GPL2 license.
42 |
43 | # Downloading
44 |
45 | SandboxBerry is a windows application written in C# and uses the .NET Framework 4.5.
46 | You'll need .NET 4.5 Framework installed already (most recent PCs will have it)
47 |
48 | * Download the latest Zip from the [GitHub Releases](https://github.com/codeulike/SandboxBerry/releases) page
49 | * Unzip it in a folder and run SandboxBerry.exe
50 | * Read the documentation in the [Wiki](https://github.com/codeulike/SandboxBerry/wiki)
51 |
52 | # Running from Source
53 |
54 | Visual Studio 2012 was used for the initial project but it should be easily loadable in more recent versions of VS.
55 | Download the solution and ooen it in VS.
56 | You'll need .NET 4.5 installed.
57 |
58 | # Getting Started
59 |
60 | Refer to the [Wiki](https://github.com/codeulike/SandboxBerry/wiki) for instructions on how to use SandboxBerry
61 |
62 |
--------------------------------------------------------------------------------
/Sandboxberry/AboutForm.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace Sandboxberry
2 | {
3 | partial class AboutForm
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AboutForm));
32 | this.uxAboutText = new System.Windows.Forms.TextBox();
33 | this.uxOkButton = new System.Windows.Forms.Button();
34 | this.uxHomeLink = new System.Windows.Forms.LinkLabel();
35 | this.uxIconsLink = new System.Windows.Forms.LinkLabel();
36 | this.SuspendLayout();
37 | //
38 | // uxAboutText
39 | //
40 | this.uxAboutText.Location = new System.Drawing.Point(12, 12);
41 | this.uxAboutText.Multiline = true;
42 | this.uxAboutText.Name = "uxAboutText";
43 | this.uxAboutText.ReadOnly = true;
44 | this.uxAboutText.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
45 | this.uxAboutText.Size = new System.Drawing.Size(368, 185);
46 | this.uxAboutText.TabIndex = 0;
47 | this.uxAboutText.TextChanged += new System.EventHandler(this.uxAboutText_TextChanged);
48 | //
49 | // uxOkButton
50 | //
51 | this.uxOkButton.DialogResult = System.Windows.Forms.DialogResult.OK;
52 | this.uxOkButton.Location = new System.Drawing.Point(297, 239);
53 | this.uxOkButton.Name = "uxOkButton";
54 | this.uxOkButton.Size = new System.Drawing.Size(82, 23);
55 | this.uxOkButton.TabIndex = 1;
56 | this.uxOkButton.Text = "OK";
57 | this.uxOkButton.UseVisualStyleBackColor = true;
58 | this.uxOkButton.Click += new System.EventHandler(this.uxOkButton_Click);
59 | //
60 | // uxHomeLink
61 | //
62 | this.uxHomeLink.AutoSize = true;
63 | this.uxHomeLink.Location = new System.Drawing.Point(13, 212);
64 | this.uxHomeLink.Name = "uxHomeLink";
65 | this.uxHomeLink.Size = new System.Drawing.Size(128, 13);
66 | this.uxHomeLink.TabIndex = 2;
67 | this.uxHomeLink.TabStop = true;
68 | this.uxHomeLink.Text = "SandboxBerry Homepage";
69 | this.uxHomeLink.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.uxHomeLink_LinkClicked);
70 | //
71 | // uxIconsLink
72 | //
73 | this.uxIconsLink.AutoSize = true;
74 | this.uxIconsLink.Location = new System.Drawing.Point(302, 212);
75 | this.uxIconsLink.Name = "uxIconsLink";
76 | this.uxIconsLink.Size = new System.Drawing.Size(77, 13);
77 | this.uxIconsLink.TabIndex = 3;
78 | this.uxIconsLink.TabStop = true;
79 | this.uxIconsLink.Text = "Icons by Icon8";
80 | this.uxIconsLink.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.uxIconsLink_LinkClicked);
81 | //
82 | // AboutForm
83 | //
84 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
85 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
86 | this.ClientSize = new System.Drawing.Size(392, 274);
87 | this.Controls.Add(this.uxIconsLink);
88 | this.Controls.Add(this.uxHomeLink);
89 | this.Controls.Add(this.uxOkButton);
90 | this.Controls.Add(this.uxAboutText);
91 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
92 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
93 | this.MaximizeBox = false;
94 | this.MinimizeBox = false;
95 | this.Name = "AboutForm";
96 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
97 | this.Text = "About SandboxBerry";
98 | this.ResumeLayout(false);
99 | this.PerformLayout();
100 |
101 | }
102 |
103 | #endregion
104 |
105 | private System.Windows.Forms.TextBox uxAboutText;
106 | private System.Windows.Forms.Button uxOkButton;
107 | private System.Windows.Forms.LinkLabel uxHomeLink;
108 | private System.Windows.Forms.LinkLabel uxIconsLink;
109 | }
110 | }
--------------------------------------------------------------------------------
/Sandboxberry/AboutForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Diagnostics;
6 | using System.Drawing;
7 | using System.Linq;
8 | using System.Reflection;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 | using System.Windows.Forms;
12 |
13 | namespace Sandboxberry
14 | {
15 | public partial class AboutForm : Form
16 | {
17 | public AboutForm()
18 | {
19 | InitializeComponent();
20 | PopulateAbout();
21 | }
22 |
23 | private void uxOkButton_Click(object sender, EventArgs e)
24 | {
25 | this.Close();
26 | }
27 |
28 | private void PopulateAbout()
29 | {
30 | Version v = Assembly.GetEntryAssembly().GetName().Version;
31 | String verString = v.ToString();
32 |
33 | StringBuilder sb = new StringBuilder();
34 | sb.Append(Environment.NewLine);
35 | sb.Append("SandboxBerry" + Environment.NewLine + Environment.NewLine);
36 | sb.AppendFormat("Version {0}" + Environment.NewLine + Environment.NewLine, verString);
37 | sb.Append("(C) Ian Finch 2017" + Environment.NewLine + Environment.NewLine);
38 | sb.Append("This program is free software; you can redistribute it and/or ");
39 | sb.Append("modify it under the terms of the GNU General Public License ");
40 | sb.Append("as published by the Free Software Foundation; either version 2 ");
41 | sb.Append("of the License, or (at your option) any later version." + Environment.NewLine);
42 | sb.Append(Environment.NewLine);
43 | sb.Append("This program is distributed in the hope that it will be useful, ");
44 | sb.Append("but WITHOUT ANY WARRANTY; without even the implied warranty of ");
45 | sb.Append("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ");
46 | sb.Append("GNU General Public License for more details." + Environment.NewLine);
47 | sb.Append(Environment.NewLine);
48 | sb.Append("You should have received a copy of the GNU General Public License ");
49 | sb.Append("along with this program; if not, write to the Free Software ");
50 | sb.Append("Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA." + Environment.NewLine);
51 |
52 | uxAboutText.Text = sb.ToString();
53 | uxAboutText.Select(0, 0);
54 | }
55 |
56 | private void uxHomeLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
57 | {
58 | ProcessStartInfo sInfo = new ProcessStartInfo("https://github.com/codeulike/sandboxberry");
59 | Process.Start(sInfo);
60 | }
61 |
62 | private void uxIconsLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
63 | {
64 | ProcessStartInfo sInfo = new ProcessStartInfo("https://icons8.com");
65 | Process.Start(sInfo);
66 |
67 | }
68 |
69 | private void uxAboutText_TextChanged(object sender, EventArgs e)
70 | {
71 |
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/Sandboxberry/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | 0
15 |
16 |
17 | 0
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Sandboxberry/Berryicon48.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeulike/SandboxBerry/2d1ed91fba78594b344e5fe57cefb14be89460da/Sandboxberry/Berryicon48.ico
--------------------------------------------------------------------------------
/Sandboxberry/MainForm.cs:
--------------------------------------------------------------------------------
1 | // SandboxBerry - tool for copying test data into Salesforce sandboxes
2 | // Copyright (C) 2017 Ian Finch
3 | //
4 | // This program is free software; you can redistribute it and/or
5 | // modify it under the terms of the GNU General Public License
6 | // as published by the Free Software Foundation; either version 2
7 | // of the License, or (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program; if not, write to the Free Software
16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 |
18 | using System;
19 | using System.Collections.Generic;
20 | using System.ComponentModel;
21 | using System.Data;
22 | using System.Drawing;
23 | using System.Linq;
24 | using System.Text;
25 | using System.Threading.Tasks;
26 | using System.Windows.Forms;
27 | using log4net;
28 |
29 | using SandboxberryLib;
30 | using SandboxberryLib.InstructionsModel;
31 | using Sandboxberry.Properties;
32 |
33 | namespace Sandboxberry
34 | {
35 | public partial class MainForm : Form
36 | {
37 | private static readonly ILog logger = LogManager.GetLogger(typeof(MainForm));
38 | private static readonly int CONST_MaxVisibleLogSize = 20000;
39 |
40 | public MainForm()
41 | {
42 | InitializeComponent();
43 | uxOpenFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
44 | uxSourceUrl.SelectedIndex = 0;
45 | uxTargetUrl.SelectedIndex = 0;
46 | uxWaitPicture.Visible = false;
47 | RetrieveUserSettings();
48 | }
49 |
50 | // after serious error, disable everything
51 | public void DisableForm()
52 | {
53 | uxWaitPicture.Visible = false;
54 | foreach (Control c in this.Controls)
55 | {
56 | c.Enabled = false;
57 | }
58 |
59 |
60 | }
61 |
62 | public void SaveUserSettings()
63 | {
64 |
65 | Settings.Default["SetSourceUrl"] = uxSourceUrl.SelectedIndex;
66 | Settings.Default["SetSourceUsername"] = uxSourceUsername.Text;
67 | Settings.Default["SetTargetUrl"] = uxTargetUrl.SelectedIndex;
68 | Settings.Default["SetTargetUsername"] = uxTargetUsername.Text;
69 | Settings.Default["SetInstructionsFile"] = uxInstructionsFilename.Text;
70 | Settings.Default.Save();
71 | }
72 |
73 | public void RetrieveUserSettings()
74 | {
75 | try
76 | {
77 | if (Settings.Default["SetSourceUsername"] != null)
78 | {
79 | uxSourceUrl.SelectedIndex = (int)(Settings.Default["SetSourceUrl"]);
80 | uxSourceUsername.Text = Settings.Default["SetSourceUsername"].ToString();
81 | uxTargetUrl.SelectedIndex = (int)(Settings.Default["SetTargetUrl"]);
82 | uxTargetUsername.Text = Settings.Default["SetTargetUsername"].ToString();
83 | uxInstructionsFilename.Text = Settings.Default["SetInstructionsFile"].ToString();
84 | }
85 |
86 | }
87 | catch (Exception e)
88 | {
89 | logger.Error("Error while retrieving user settings", e);
90 | }
91 |
92 | }
93 |
94 | private void uxLaunchFileOpen_Click(object sender, EventArgs e)
95 | {
96 | // set initial directory if value
97 | string lastFile = uxInstructionsFilename.Text;
98 | if (!String.IsNullOrEmpty(lastFile))
99 | {
100 | if (System.IO.Directory.Exists(lastFile) || System.IO.File.Exists(lastFile))
101 | uxOpenFileDialog.InitialDirectory = System.IO.Path.GetDirectoryName(lastFile);
102 | }
103 | if (uxOpenFileDialog.ShowDialog() == DialogResult.OK)
104 | {
105 | uxInstructionsFilename.Text = uxOpenFileDialog.FileName;
106 | }
107 | }
108 |
109 | private async void uxStartButton_Click(object sender, EventArgs e)
110 | {
111 | ShowUiProcessStarted();
112 | SaveUserSettings();
113 |
114 |
115 | try
116 | {
117 | var instructions = LoadInstructions();
118 | var progress = new Progress(t => ShowMessage(t));
119 | await Task.Factory.StartNew(() => new PopulateSandbox(instructions).Start(progress),
120 | TaskCreationOptions.LongRunning);
121 |
122 | ShowMessage(string.Format("Finished."));
123 | ShowUiProcessEnded();
124 | }
125 | catch (Exception ex)
126 | {
127 | logger.Error("StartButton_Click caught an error", ex);
128 | ShowMessage("******************");
129 | ShowMessage(string.Format("Unexpected error: {0} \r\n\r\n See Log.txt file for details",ex.Message));
130 | ShowUiProcessEnded();
131 | MessageBox.Show(string.Format("Unexpected error: {0} \r\n\r\n See Log.txt file for details", ex.Message), "Unexpected Error",
132 | MessageBoxButtons.OK, MessageBoxIcon.Error);
133 |
134 | }
135 |
136 |
137 | }
138 |
139 | private void ShowUiProcessStarted()
140 | {
141 | uxStartButton.Enabled = false;
142 | uxWaitPicture.Visible = true;
143 | clearTargetDataToolStripMenuItem.Enabled = false;
144 |
145 | }
146 |
147 | private void ShowUiProcessEnded()
148 | {
149 | uxStartButton.Enabled = true;
150 | uxWaitPicture.Visible = false;
151 | clearTargetDataToolStripMenuItem.Enabled = true;
152 | }
153 |
154 | private SbbInstructionSet LoadInstructions()
155 | {
156 | ShowMessage(string.Format("Loading instructions from {0} ...", uxInstructionsFilename.Text));
157 | var instructions = SbbInstructionSet.LoadFromFile(uxInstructionsFilename.Text);
158 | ShowMessage(string.Format("Instructions loaded."));
159 |
160 | // add credentials to instructions
161 | instructions.SourceCredentials = GetSourceCredentials();
162 | instructions.TargetCredentuals = GetTargetCredentials();
163 | return instructions;
164 | }
165 |
166 | private SbbCredentials GetSourceCredentials()
167 | {
168 | var sourceCred = new SbbCredentials();
169 | sourceCred.SalesforceUrl = "https://test.salesforce.com/services/Soap/u/32.0";
170 | if (uxSourceUrl.SelectedItem != null && uxSourceUrl.SelectedItem.ToString().StartsWith("Live"))
171 | sourceCred.SalesforceUrl = "https://login.salesforce.com/services/Soap/u/32.0";
172 | sourceCred.SalesforceLogin = uxSourceUsername.Text;
173 | sourceCred.SalesforcePassword = uxSourcePassword.Text;
174 | return sourceCred;
175 | }
176 |
177 | private SbbCredentials GetTargetCredentials()
178 | {
179 | var targetCred = new SbbCredentials();
180 | targetCred.SalesforceUrl = "https://test.salesforce.com/services/Soap/u/32.0";
181 | targetCred.SalesforceLogin = uxTargetUsername.Text;
182 | targetCred.SalesforcePassword = uxTargetPassword.Text;
183 | return targetCred;
184 | }
185 |
186 | public void ShowMessage(string mess)
187 | {
188 | logger.DebugFormat("Progress message: {0}", mess);
189 | uxProgressBox.Text += string.Format("{0}{1}",
190 | mess, Environment.NewLine);
191 | if (uxProgressBox.Text.Length > CONST_MaxVisibleLogSize)
192 | uxProgressBox.Text = "..." + uxProgressBox.Text.Substring(uxProgressBox.Text.Length - (CONST_MaxVisibleLogSize-4));
193 | uxProgressBox.SelectionStart = uxProgressBox.Text.Length;
194 | uxProgressBox.ScrollToCaret();
195 | }
196 |
197 | private async void clearTargetDataToolStripMenuItem_Click(object sender, EventArgs e)
198 | {
199 | logger.DebugFormat("Asking user to confirm data clear");
200 | var msResult = MessageBox.Show(string.Format("This will clear all data from Target sandbox for objects listed in Instructions file \r\n {0} \r\n \r\n Are you sure you want to do this?", uxInstructionsFilename.Text),
201 | "Clear Target Data?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
202 | if (msResult == System.Windows.Forms.DialogResult.Yes)
203 | {
204 | logger.DebugFormat("User confirmed clear of data in {0}", uxInstructionsFilename.Text);
205 | //ToDo make this an option in the UI
206 | Boolean ignoreFilters = false;
207 |
208 | ShowUiProcessStarted();
209 | ShowMessage(string.Format("Starting clear of target data ..."));
210 | if (ignoreFilters)
211 | ShowMessage(string.Format(" (ignoreFilters flag set to true)"));
212 | try
213 | {
214 | var instructions = LoadInstructions();
215 | var progress = new Progress(t => ShowMessage(t));
216 | await Task.Factory.StartNew(() => new PopulateSandbox(instructions).DeleteTargetData(progress, ignoreFilters),
217 | TaskCreationOptions.LongRunning);
218 |
219 | ShowMessage(string.Format("Finished."));
220 |
221 | ShowUiProcessEnded();
222 | }
223 | catch (Exception ex)
224 | {
225 | logger.Error("clearTargetDataToolStripMenuItem_Click caught an error", ex);
226 | ShowMessage("******************");
227 | ShowMessage(string.Format("Unexpected error: {0} \r\n\r\n See Log.txt file for details", ex.Message));
228 | ShowUiProcessEnded();
229 | MessageBox.Show(string.Format("Unexpected error: {0} \r\n\r\n See Log.txt file for details", ex.Message), "Unexpected Error",
230 | MessageBoxButtons.OK, MessageBoxIcon.Error);
231 |
232 | }
233 |
234 |
235 | }
236 | }
237 |
238 | private void uxTestLoginSource_Click(object sender, EventArgs e)
239 | {
240 | var sourceCred = GetSourceCredentials();
241 | var sesh = new SalesforceSession(sourceCred);
242 | uxTestLoginSourceLabel.Text = "Testing login ...";
243 | uxTestLoginSourceLabel.Visible = true;
244 | Cursor.Current = Cursors.WaitCursor;
245 | try
246 | {
247 | sesh.TestLogin();
248 | uxTestLoginSourceLabel.Text = "Login OK";
249 | Cursor.Current = Cursors.Default;
250 | }
251 | catch (Exception ex)
252 | {
253 | uxTestLoginSourceLabel.Text = "Login failed";
254 | Cursor.Current = Cursors.Default;
255 | MessageBox.Show(string.Format("Test login failed for Source \r\n\r\n {0}", ex.Message), "Test login failed", MessageBoxButtons.OK, MessageBoxIcon.Warning);
256 | }
257 | }
258 |
259 | private void uxTestLoginTarget_Click(object sender, EventArgs e)
260 | {
261 | var targetCred = GetTargetCredentials();
262 | var sesh = new SalesforceSession(targetCred);
263 | uxTestLoginTargetLabel.Text = "Testing login ...";
264 | uxTestLoginTargetLabel.Visible = true;
265 | Cursor.Current = Cursors.WaitCursor;
266 | try
267 | {
268 | sesh.TestLogin();
269 | uxTestLoginTargetLabel.Text = "Login OK";
270 | Cursor.Current = Cursors.Default;
271 | }
272 | catch (Exception ex)
273 | {
274 | uxTestLoginTargetLabel.Text = "Login failed";
275 | Cursor.Current = Cursors.Default;
276 | MessageBox.Show(string.Format("Test login failed for Target \r\n\r\n {0}", ex.Message), "Test login failed", MessageBoxButtons.OK, MessageBoxIcon.Warning);
277 | }
278 | }
279 |
280 | private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
281 | {
282 | using (var about = new AboutForm())
283 | {
284 | about.ShowDialog();
285 | }
286 | }
287 |
288 |
289 |
290 |
291 | }
292 | }
293 |
--------------------------------------------------------------------------------
/Sandboxberry/Program.cs:
--------------------------------------------------------------------------------
1 | // SandboxBerry - tool for copying test data into Salesforce sandboxes
2 | // Copyright (C) 2017 Ian Finch
3 | //
4 | // This program is free software; you can redistribute it and/or
5 | // modify it under the terms of the GNU General Public License
6 | // as published by the Free Software Foundation; either version 2
7 | // of the License, or (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program; if not, write to the Free Software
16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 |
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Linq;
21 | using System.Threading.Tasks;
22 | using System.Windows.Forms;
23 | using log4net;
24 |
25 | namespace Sandboxberry
26 | {
27 | static class Program
28 | {
29 | private static readonly ILog logger = LogManager.GetLogger(typeof(Program));
30 |
31 | private static MainForm _mainForm = null;
32 |
33 | ///
34 | /// The main entry point for the application.
35 | ///
36 | [STAThread]
37 | static void Main()
38 | {
39 | logger.DebugFormat("Main() starting");
40 | Application.ThreadException += Application_ThreadException;
41 | Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
42 | AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
43 | Application.EnableVisualStyles();
44 | Application.SetCompatibleTextRenderingDefault(false);
45 | _mainForm = new MainForm();
46 | Application.Run(_mainForm);
47 | logger.DebugFormat("Main() finishing");
48 | }
49 |
50 | static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
51 | {
52 |
53 | Exception ex = e.ExceptionObject as Exception;
54 | logger.Error("CurrentDomain_UnhandledException caught an error", ex);
55 |
56 | MessageBox.Show(string.Format("Unexpected error: {0} \r\n\r\n See log for details", ex.Message), "Unexpected Error",
57 | MessageBoxButtons.OK, MessageBoxIcon.Error);
58 | if (_mainForm != null)
59 | _mainForm.DisableForm();
60 | else
61 | Application.Exit();
62 |
63 | }
64 |
65 | static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
66 | {
67 | // nb this catches the original base exception, discarding any outer ones, see http://stackoverflow.com/q/8565761/22194
68 | Exception ex = e.Exception;
69 | logger.Error("Application_ThreadException caught an error", ex);
70 |
71 | MessageBox.Show(string.Format("Unexpected error: {0} \r\n\r\n See log for details", ex.Message), "Unexpected Error",
72 | MessageBoxButtons.OK, MessageBoxIcon.Error);
73 | if (_mainForm != null)
74 | _mainForm.DisableForm();
75 | else
76 | Application.Exit();
77 |
78 |
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Sandboxberry/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | // SandboxBerry - tool for copying test data into Salesforce sandboxes
2 | // Copyright (C) 2017 Ian Finch
3 | //
4 | // This program is free software; you can redistribute it and/or
5 | // modify it under the terms of the GNU General Public License
6 | // as published by the Free Software Foundation; either version 2
7 | // of the License, or (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program; if not, write to the Free Software
16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 |
18 | using System.Reflection;
19 | using System.Runtime.CompilerServices;
20 | using System.Runtime.InteropServices;
21 |
22 | // General Information about an assembly is controlled through the following
23 | // set of attributes. Change these attribute values to modify the information
24 | // associated with an assembly.
25 | [assembly: AssemblyTitle("Sandboxberry")]
26 | [assembly: AssemblyDescription("")]
27 | [assembly: AssemblyConfiguration("")]
28 | [assembly: AssemblyCompany("")]
29 | [assembly: AssemblyProduct("Sandboxberry")]
30 | [assembly: AssemblyCopyright("Copyright © 2017")]
31 | [assembly: AssemblyTrademark("")]
32 | [assembly: AssemblyCulture("")]
33 |
34 | // Setting ComVisible to false makes the types in this assembly not visible
35 | // to COM components. If you need to access a type in this assembly from
36 | // COM, set the ComVisible attribute to true on that type.
37 | [assembly: ComVisible(false)]
38 |
39 | // The following GUID is for the ID of the typelib if this project is exposed to COM
40 | [assembly: Guid("688e522d-3005-4082-bf49-7c43f8b3bf33")]
41 |
42 | // Version information for an assembly consists of the following four values:
43 | //
44 | // Major Version
45 | // Minor Version
46 | // Build Number
47 | // Revision
48 | //
49 | // You can specify all the values or you can default the Build and Revision Numbers
50 | // by using the '*' as shown below:
51 | // [assembly: AssemblyVersion("1.0.*")]
52 | [assembly: AssemblyVersion("1.3.0.0")]
53 | [assembly: AssemblyFileVersion("1.3.0.0")]
54 |
55 |
56 | [assembly: log4net.Config.XmlConfigurator(ConfigFile = "logging.config", Watch = true)]
57 |
--------------------------------------------------------------------------------
/Sandboxberry/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.34014
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Sandboxberry.Properties
12 | {
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// Returns the cached ResourceManager instance used by this class.
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Sandboxberry.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// Overrides the current thread's CurrentUICulture property for all
56 | /// resource lookups using this strongly typed resource class.
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Sandboxberry/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/Sandboxberry/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.34014
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Sandboxberry.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 |
26 | [global::System.Configuration.UserScopedSettingAttribute()]
27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
28 | [global::System.Configuration.DefaultSettingValueAttribute("0")]
29 | public int SetSourceUrl {
30 | get {
31 | return ((int)(this["SetSourceUrl"]));
32 | }
33 | set {
34 | this["SetSourceUrl"] = value;
35 | }
36 | }
37 |
38 | [global::System.Configuration.UserScopedSettingAttribute()]
39 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
40 | [global::System.Configuration.DefaultSettingValueAttribute("0")]
41 | public int SetTargetUrl {
42 | get {
43 | return ((int)(this["SetTargetUrl"]));
44 | }
45 | set {
46 | this["SetTargetUrl"] = value;
47 | }
48 | }
49 |
50 | [global::System.Configuration.UserScopedSettingAttribute()]
51 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
52 | [global::System.Configuration.DefaultSettingValueAttribute("")]
53 | public string SetSourceUsername {
54 | get {
55 | return ((string)(this["SetSourceUsername"]));
56 | }
57 | set {
58 | this["SetSourceUsername"] = value;
59 | }
60 | }
61 |
62 | [global::System.Configuration.UserScopedSettingAttribute()]
63 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
64 | [global::System.Configuration.DefaultSettingValueAttribute("")]
65 | public string SetTargetUsername {
66 | get {
67 | return ((string)(this["SetTargetUsername"]));
68 | }
69 | set {
70 | this["SetTargetUsername"] = value;
71 | }
72 | }
73 |
74 | [global::System.Configuration.UserScopedSettingAttribute()]
75 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
76 | [global::System.Configuration.DefaultSettingValueAttribute("")]
77 | public string SetInstructionsFile {
78 | get {
79 | return ((string)(this["SetInstructionsFile"]));
80 | }
81 | set {
82 | this["SetInstructionsFile"] = value;
83 | }
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/Sandboxberry/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 0
7 |
8 |
9 | 0
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/Sandboxberry/Resources/Berryicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeulike/SandboxBerry/2d1ed91fba78594b344e5fe57cefb14be89460da/Sandboxberry/Resources/Berryicon.png
--------------------------------------------------------------------------------
/Sandboxberry/Resources/Berryicon48.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeulike/SandboxBerry/2d1ed91fba78594b344e5fe57cefb14be89460da/Sandboxberry/Resources/Berryicon48.ico
--------------------------------------------------------------------------------
/Sandboxberry/Resources/Berryicon48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeulike/SandboxBerry/2d1ed91fba78594b344e5fe57cefb14be89460da/Sandboxberry/Resources/Berryicon48.png
--------------------------------------------------------------------------------
/Sandboxberry/Resources/loader.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeulike/SandboxBerry/2d1ed91fba78594b344e5fe57cefb14be89460da/Sandboxberry/Resources/loader.gif
--------------------------------------------------------------------------------
/Sandboxberry/Sandboxberry.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {108FA37A-1DA5-4189-AF60-167567E149E5}
8 | WinExe
9 | Properties
10 | Sandboxberry
11 | Sandboxberry
12 | v4.5
13 | 512
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | AnyCPU
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 | Berryicon48.ico
36 |
37 |
38 |
39 | ..\packages\log4net.2.0.3\lib\net40-full\log4net.dll
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | Form
55 |
56 |
57 | AboutForm.cs
58 |
59 |
60 | Form
61 |
62 |
63 | MainForm.cs
64 |
65 |
66 |
67 |
68 | AboutForm.cs
69 |
70 |
71 | MainForm.cs
72 |
73 |
74 | ResXFileCodeGenerator
75 | Resources.Designer.cs
76 | Designer
77 |
78 |
79 | True
80 | Resources.resx
81 |
82 |
83 | Always
84 |
85 |
86 |
87 | SettingsSingleFileGenerator
88 | Settings.Designer.cs
89 |
90 |
91 | True
92 | Settings.settings
93 | True
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 | {2057ff00-1368-40f2-a79a-b2ce6d3cba77}
102 | SandboxberryLib
103 |
104 |
105 |
106 |
107 |
108 |
109 |
116 |
--------------------------------------------------------------------------------
/Sandboxberry/logging.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Sandboxberry/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/SandboxberryLib/InstructionsModel/SbbCredentials.cs:
--------------------------------------------------------------------------------
1 | // SandboxBerry - tool for copying test data into Salesforce sandboxes
2 | // Copyright (C) 2017 Ian Finch
3 | //
4 | // This program is free software; you can redistribute it and/or
5 | // modify it under the terms of the GNU General Public License
6 | // as published by the Free Software Foundation; either version 2
7 | // of the License, or (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program; if not, write to the Free Software
16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 |
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Linq;
21 | using System.Text;
22 | using System.Threading.Tasks;
23 |
24 | namespace SandboxberryLib.InstructionsModel
25 | {
26 | public class SbbCredentials
27 | {
28 | public string SalesforceUrl { get; set; }
29 | public string SalesforceLogin { get; set; }
30 | public string SalesforcePassword { get; set; }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/SandboxberryLib/InstructionsModel/SbbFieldOption.cs:
--------------------------------------------------------------------------------
1 | // SandboxBerry - tool for copying test data into Salesforce sandboxes
2 | // Copyright (C) 2017 Ian Finch
3 | //
4 | // This program is free software; you can redistribute it and/or
5 | // modify it under the terms of the GNU General Public License
6 | // as published by the Free Software Foundation; either version 2
7 | // of the License, or (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program; if not, write to the Free Software
16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 | using System;
18 | using System.Collections.Generic;
19 | using System.Linq;
20 | using System.Text;
21 | using System.Threading.Tasks;
22 | using System.Xml.Serialization;
23 |
24 | namespace SandboxberryLib.InstructionsModel
25 | {
26 | public class SbbFieldOption
27 | {
28 | [XmlAttribute]
29 | public string ApiName { get; set; }
30 |
31 | // defaults to false during deserialization
32 | [XmlAttribute]
33 | public bool Skip { get; set; }
34 |
35 | // this lets schema generator know Skip is not mandatory
36 | [XmlIgnore]
37 | public bool SkipSpecified
38 | {
39 | get { return this.Skip; }
40 | }
41 |
42 | [XmlAttribute]
43 | public string ReplaceText { get; set; }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/SandboxberryLib/InstructionsModel/SbbInstructionSet.cs:
--------------------------------------------------------------------------------
1 | // SandboxBerry - tool for copying test data into Salesforce sandboxes
2 | // Copyright (C) 2017 Ian Finch
3 | //
4 | // This program is free software; you can redistribute it and/or
5 | // modify it under the terms of the GNU General Public License
6 | // as published by the Free Software Foundation; either version 2
7 | // of the License, or (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program; if not, write to the Free Software
16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 |
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Linq;
21 | using System.Text;
22 | using System.Threading.Tasks;
23 | using System.Xml.Serialization;
24 | using System.Xml.Schema;
25 | using System.Xml;
26 | using System.Reflection;
27 | using log4net;
28 |
29 | namespace SandboxberryLib.InstructionsModel
30 | {
31 | public class SbbInstructionSet
32 | {
33 | private static readonly ILog logger = LogManager.GetLogger(typeof(SbbInstructionSet));
34 |
35 |
36 |
37 | [XmlIgnore]
38 | public SbbCredentials SourceCredentials { get; set; }
39 |
40 | [XmlIgnore]
41 | public SbbCredentials TargetCredentuals { get; set; }
42 |
43 | public List SbbObjects { get; set; }
44 |
45 | public static void SaveToFile(string filename, SbbInstructionSet inst)
46 | {
47 |
48 | using (var writer = new System.IO.StreamWriter(filename))
49 | {
50 | var serializer = new XmlSerializer(inst.GetType());
51 | serializer.Serialize(writer, inst);
52 | writer.Flush();
53 | }
54 |
55 | }
56 |
57 | public static SbbInstructionSet LoadFromFile(string filename)
58 | {
59 | XmlReaderSettings settings = new XmlReaderSettings();
60 | settings.Schemas.Add(GetInstructionSetSchema());
61 | settings.ValidationType = ValidationType.Schema;
62 | settings.ValidationFlags =
63 | XmlSchemaValidationFlags.ProcessIdentityConstraints |
64 | XmlSchemaValidationFlags.ReportValidationWarnings;
65 | XmlSchemaException firstException = null;
66 | settings.ValidationEventHandler +=
67 | delegate(object sender, ValidationEventArgs args)
68 | {
69 | if (args.Severity == XmlSeverityType.Warning)
70 | {
71 | logger.DebugFormat("Warning from Xml Validations: {0}", args.Message);
72 | }
73 | else
74 | {
75 | if (firstException == null)
76 | {
77 | firstException = args.Exception;
78 | }
79 |
80 | logger.Error(string.Format("Error from Xml Validation at Line {0} Pos {1}",
81 | args.Exception.LineNumber, args.Exception.LinePosition), args.Exception);
82 | }
83 | };
84 |
85 | var res = new SbbInstructionSet();
86 | using (var stream = System.IO.File.OpenRead(filename))
87 | {
88 | using (XmlReader reader = XmlReader.Create(stream, settings))
89 | {
90 | XmlSerializer ser = new XmlSerializer(res.GetType());
91 | res = ser.Deserialize(reader) as SbbInstructionSet;
92 | }
93 |
94 | }
95 |
96 | if (firstException != null)
97 | {
98 | throw new ApplicationException(string.Format("Could not load instruction files due to XML validation error at Line {0} Position {1}: {2}",
99 | firstException.LineNumber, firstException.LinePosition, firstException.Message), firstException);
100 | }
101 |
102 | return res;
103 | }
104 |
105 | public static XmlSchema GetInstructionSetSchema()
106 | {
107 | XmlSchema schema = null;
108 | using(var reader = XmlReader.Create(Assembly.GetExecutingAssembly().GetManifestResourceStream("SandboxberryLib.Resources.SbbInstructionSetSchema.xsd")))
109 | {
110 | schema = XmlSchema.Read(reader,
111 | new ValidationEventHandler(
112 | delegate(Object sender, ValidationEventArgs e)
113 | {
114 | logger.Error(string.Format("Error while loading Schema File"), e.Exception);
115 | throw new ApplicationException(string.Format("Schema File Validation: {0}", e.Message), e.Exception);
116 | }));
117 | }
118 | return schema;
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/SandboxberryLib/InstructionsModel/SbbObject.cs:
--------------------------------------------------------------------------------
1 | // SandboxBerry - tool for copying test data into Salesforce sandboxes
2 | // Copyright (C) 2017 Ian Finch
3 | //
4 | // This program is free software; you can redistribute it and/or
5 | // modify it under the terms of the GNU General Public License
6 | // as published by the Free Software Foundation; either version 2
7 | // of the License, or (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program; if not, write to the Free Software
16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 |
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Linq;
21 | using System.Text;
22 | using System.Threading.Tasks;
23 | using System.Xml.Serialization;
24 |
25 | namespace SandboxberryLib.InstructionsModel
26 | {
27 | public class SbbObject
28 | {
29 | public SbbObject()
30 | {
31 | this.SbbFieldOptions = new List();
32 | }
33 |
34 | [XmlAttribute]
35 | public string ApiName { get; set; }
36 | [XmlAttribute]
37 | public string Filter { get; set; }
38 |
39 | public List SbbFieldOptions { get; set; }
40 |
41 | // controls whether SbbFieldOptions list is serialized
42 | [XmlIgnore]
43 | public bool SbbFieldOptionsSpecified
44 | {
45 | get { return (SbbFieldOptions != null && SbbFieldOptions.Count > 0); }
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/SandboxberryLib/ObjectTransformer.cs:
--------------------------------------------------------------------------------
1 | // SandboxBerry - tool for copying test data into Salesforce sandboxes
2 | // Copyright (C) 2017 Ian Finch
3 | //
4 | // This program is free software; you can redistribute it and/or
5 | // modify it under the terms of the GNU General Public License
6 | // as published by the Free Software Foundation; either version 2
7 | // of the License, or (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program; if not, write to the Free Software
16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 |
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Linq;
21 | using System.Text;
22 | using System.Threading.Tasks;
23 | using SandboxberryLib.InstructionsModel;
24 | using SandboxberryLib.ResultsModel;
25 | using SandboxberryLib.SalesforcePartnerApi;
26 | using log4net;
27 | using System.Xml;
28 |
29 | namespace SandboxberryLib
30 | {
31 | public class ObjectTransformer
32 | {
33 | private static readonly ILog logger = LogManager.GetLogger(typeof(ObjectTransformer));
34 |
35 | public RelationMapper RelationMapper { get; set; }
36 |
37 | public string RecursiveRelationshipField { get; set; }
38 |
39 | public Dictionary ObjectRelationships { get; set; }
40 |
41 | public List InactiveUserIds { get; set; }
42 |
43 | public List MissingUserIds { get; set; }
44 |
45 | public string CurrentUserId { get; set; }
46 |
47 | public SbbObject SbbObjectInstructions { get; set; }
48 |
49 | public void ApplyTransformations(sObjectWrapper wrap)
50 | {
51 | CorrectInactiveUser(wrap.sObj, this.InactiveUserIds, this.CurrentUserId);
52 | if (this.RecursiveRelationshipField != null)
53 | RememberRecursiveId(wrap, this.RecursiveRelationshipField);
54 | FixRelatedIds(wrap.sObj, this.ObjectRelationships);
55 | RemoveIdFromSObject(wrap.sObj);
56 |
57 | foreach (var fieldOptions in SbbObjectInstructions.SbbFieldOptions)
58 | {
59 | XmlElement fieldNode = wrap.sObj.Any.FirstOrDefault(e => e.LocalName == fieldOptions.ApiName);
60 | if (fieldNode == null)
61 | {
62 | logger.DebugFormat("SbbFieldOption specified for {0}.{1} but could not find field - perhaps removed for this row by relationship mapper?",
63 | SbbObjectInstructions.ApiName, fieldOptions.ApiName);
64 | }
65 | else
66 | {
67 | if (!string.IsNullOrEmpty(fieldOptions.ReplaceText))
68 | {
69 | fieldNode.InnerText = fieldOptions.ReplaceText;
70 | fieldNode.IsEmpty = false;
71 |
72 | fieldNode.Attributes.RemoveNamedItem("xsi:nil");
73 | }
74 | if (fieldOptions.Skip)
75 | {
76 | wrap.sObj.Any = wrap.sObj.Any.Where(f => f.LocalName != fieldOptions.ApiName).ToArray();
77 | }
78 | }
79 |
80 | }
81 |
82 | }
83 |
84 |
85 |
86 | public void CorrectInactiveUser(sObject obj, List inactiveUserIds, string replacementUserID)
87 | {
88 | XmlElement ownerNode = obj.Any.FirstOrDefault(e => e.LocalName == "OwnerId");
89 | if (ownerNode == null)
90 | {
91 | logger.DebugFormat("Object {0} does not have OwnerID field",
92 | obj.type);
93 | return;
94 | }
95 | if (inactiveUserIds.Contains(ownerNode.InnerText))
96 | {
97 | logger.DebugFormat("Object {0} {1} has inactive owner {2} so correcting to {3}",
98 | obj.type, obj.Id, ownerNode.InnerText, replacementUserID);
99 |
100 | ownerNode.InnerText = replacementUserID;
101 | }
102 |
103 |
104 | }
105 |
106 | public void FixRelatedIds(sObject obj, Dictionary objectRelationships)
107 | {
108 | foreach (string fieldName in objectRelationships.Keys)
109 | {
110 | string destType = objectRelationships[fieldName];
111 | XmlElement relatedIdNode = obj.Any.FirstOrDefault(e => e.LocalName == fieldName);
112 | if (relatedIdNode == null)
113 | {
114 | logger.DebugFormat("Object {0} {1} could not find data for field {2}",
115 | obj.type, obj.Id, fieldName);
116 | continue;
117 | }
118 |
119 |
120 | string currentValue = relatedIdNode.InnerText;
121 | if (!string.IsNullOrEmpty(currentValue))
122 | {
123 | if (destType == "User")
124 | {
125 | // if user id is missing from target then we need to blank
126 | if (this.MissingUserIds.Contains(currentValue))
127 | {
128 | logger.DebugFormat("Object {0} {1} lookup field {2} (points to User) has User ID {3} which is missing from Target - will clear id",
129 | obj.type, obj.Id, fieldName, currentValue);
130 | obj.Any = obj.Any.Where(e => e.LocalName != relatedIdNode.LocalName).ToArray();
131 | }
132 | }
133 | else
134 | {
135 | string replaceValue = this.RelationMapper.RecallNewId(destType, currentValue);
136 | if (replaceValue != null)
137 | {
138 | relatedIdNode.InnerText = replaceValue;
139 | logger.DebugFormat("Object {0} {1} replaced lookup field {2} (points to {3}) value {4} with {5}",
140 | obj.type, obj.Id, fieldName, destType, currentValue, replaceValue);
141 |
142 | }
143 | else
144 | {
145 | logger.DebugFormat("Object {0} {1} lookup field {2} (points to {3}) could not translate - will clear id",
146 | obj.type, obj.Id, fieldName, destType);
147 | obj.Any = obj.Any.Where(e => e.LocalName != relatedIdNode.LocalName).ToArray();
148 | }
149 | }
150 | }
151 |
152 |
153 | }
154 |
155 | }
156 |
157 | public void RemoveIdFromSObject(sObject obj)
158 | {
159 | obj.Any = obj.Any.Where(e => e.LocalName != "Id").ToArray();
160 | obj.Id = null;
161 |
162 | }
163 |
164 | private void RememberRecursiveId(ObjectTransformer.sObjectWrapper wrap, string recursiveField)
165 | {
166 | XmlElement recursiveNode = wrap.sObj.Any.FirstOrDefault(e => e.LocalName == recursiveField);
167 | wrap.RecursiveRelationshipOriginalId = recursiveNode.InnerText;
168 |
169 |
170 | }
171 |
172 |
173 |
174 | public class sObjectWrapper
175 | {
176 | public string OriginalId { get; set; }
177 | public sObject sObj { get; set; }
178 | public string NewId { get; set; }
179 | public string ErrorMessage { get; set; }
180 |
181 | public string RecursiveRelationshipField { get; set; }
182 | public string RecursiveRelationshipOriginalId { get; set; }
183 | }
184 |
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/SandboxberryLib/PopulateSandbox.cs:
--------------------------------------------------------------------------------
1 | // SandboxBerry - tool for copying test data into Salesforce sandboxes
2 | // Copyright (C) 2017 Ian Finch
3 | //
4 | // This program is free software; you can redistribute it and/or
5 | // modify it under the terms of the GNU General Public License
6 | // as published by the Free Software Foundation; either version 2
7 | // of the License, or (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program; if not, write to the Free Software
16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 |
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Linq;
21 | using System.Text;
22 | using System.Threading.Tasks;
23 | using SandboxberryLib.InstructionsModel;
24 | using SandboxberryLib.ResultsModel;
25 | using SandboxberryLib.SalesforcePartnerApi;
26 | using log4net;
27 | using System.Xml;
28 |
29 | namespace SandboxberryLib
30 | {
31 | public class PopulateSandbox
32 | {
33 | private static readonly ILog logger = LogManager.GetLogger(typeof(PopulateSandbox));
34 |
35 |
36 | private SalesforceTasks _sourceTasks;
37 | private SalesforceTasks _targetTasks;
38 |
39 | private SbbInstructionSet _instructions;
40 | private RelationMapper _relationMapper;
41 |
42 | private IProgress _progress;
43 |
44 | public PopulateSandbox(SbbInstructionSet instructions):this(instructions, new RelationMapper())
45 | {
46 | }
47 |
48 | public PopulateSandbox(SbbInstructionSet instructions, RelationMapper relMapper)
49 | {
50 | _sourceTasks = new SalesforceTasks(instructions.SourceCredentials);
51 | _targetTasks = new SalesforceTasks(instructions.TargetCredentuals);
52 | _instructions = instructions;
53 | _relationMapper = relMapper;
54 |
55 | }
56 |
57 | public PopulateSandboxResult Start()
58 | {
59 | return this.Start(null);
60 | }
61 |
62 | public void ProgressUpdate(string message)
63 | {
64 | if (_progress == null)
65 | {
66 | logger.DebugFormat("Progress message: {0}", message);
67 | }
68 | else
69 | _progress.Report(message);
70 | }
71 |
72 | public PopulateSandboxResult Start(IProgress progress)
73 | {
74 | _progress = progress;
75 | var res = new PopulateSandboxResult();
76 | ProgressUpdate("Logging in to Salesforce API ...");
77 | LoginToBoth();
78 | ProgressUpdate("Fetching metadata...");
79 | var apiNameArray = _instructions.SbbObjects.Select(o => o.ApiName).ToArray();
80 | _sourceTasks.FetchObjectMetadata(apiNameArray);
81 | ProgressUpdate("Getting inactive users...");
82 | var inactiveUserIds = _targetTasks.GetInactiveUsers();
83 | string currentUserId = _targetTasks.GetCurrentUserId();
84 | ProgressUpdate("Checking for missing users...");
85 | var sourceUserIds = _sourceTasks.GetAllUsers();
86 | var targetUserIds = _targetTasks.GetAllUsers();
87 | var missingUserIds = sourceUserIds.Except(targetUserIds).ToList();
88 | logger.DebugFormat("Found {0} users in Source that are not in Target", missingUserIds.Count());
89 |
90 | foreach (SbbObject objLoop in _instructions.SbbObjects)
91 | {
92 | ProgressUpdate(string.Format("Starting to process {0}", objLoop.ApiName));
93 | var objres = new PopulateObjectResult();
94 | var transformer = new ObjectTransformer();
95 | transformer.RelationMapper = _relationMapper;
96 | transformer.InactiveUserIds = inactiveUserIds;
97 | transformer.MissingUserIds = missingUserIds;
98 | transformer.CurrentUserId = currentUserId;
99 | transformer.SbbObjectInstructions = objLoop;
100 |
101 | objres.ApiName = objLoop.ApiName;
102 | res.ObjectResults.Add(objres);
103 |
104 | transformer.ObjectRelationships = _sourceTasks.GetObjectRelationships(objLoop.ApiName);
105 | transformer.RecursiveRelationshipField = transformer.ObjectRelationships.FirstOrDefault(d => d.Value == objLoop.ApiName).Key;
106 | if (transformer.RecursiveRelationshipField != null)
107 | logger.DebugFormat("Object {0} has a recurive relation to iteself in field {1}",
108 | objLoop.ApiName, transformer.RecursiveRelationshipField);
109 |
110 |
111 | List sourceData = null;
112 | try
113 | {
114 | sourceData = _sourceTasks.GetDataFromSObject(objLoop.ApiName, objLoop.Filter);
115 | }
116 | catch (Exception e)
117 | {
118 | string errMess = string.Format("Error while fetching data for {0}: {1}", objLoop.ApiName, e.Message);
119 | throw new ApplicationException(errMess, e);
120 | }
121 | objres.SourceRows = sourceData.Count();
122 | ProgressUpdate(string.Format("Received {0} {1} records from source", sourceData.Count, objLoop.ApiName));
123 |
124 | // get working info and transform objects
125 | var workingList = new List();
126 | foreach (sObject rowLoop in sourceData)
127 | {
128 | var wrap = new ObjectTransformer.sObjectWrapper();
129 | wrap.OriginalId = rowLoop.Id;
130 | wrap.sObj = rowLoop;
131 |
132 | transformer.ApplyTransformations(wrap);
133 |
134 |
135 | workingList.Add(wrap);
136 | }
137 |
138 | // insert objects in batches
139 | int batchSize = 100;
140 | int done = 0;
141 | bool allDone = false;
142 | if (workingList.Count == 0)
143 | allDone = true;
144 | while (!allDone)
145 | {
146 | var workBatch = workingList.Skip(done).Take(batchSize).ToList();
147 | done += workBatch.Count;
148 | if (done >= workingList.Count)
149 | allDone = true;
150 |
151 | var insertRes = _targetTasks.InsertSObjects(objLoop.ApiName,
152 | workBatch.Select(w => w.sObj).ToArray());
153 |
154 | for (int i = 0; i < insertRes.Length; i++)
155 | {
156 | if (!string.IsNullOrEmpty(insertRes[i].NewId))
157 | {
158 | workBatch[i].NewId = insertRes[i].NewId;
159 | objres.SuccessCount += 1;
160 | _relationMapper.Remember(objLoop.ApiName, workBatch[i].OriginalId, workBatch[i].NewId);
161 | }
162 | else
163 | {
164 | workBatch[i].ErrorMessage = insertRes[i].ErrorMessage;
165 | logger.WarnFormat("Error when inserting {0} {1} into target: {2}",
166 | objLoop.ApiName, workBatch[i].OriginalId, workBatch[i].ErrorMessage);
167 | objres.FailCount += 1;
168 | }
169 |
170 | }
171 |
172 | }
173 |
174 | // inserts done.
175 | // if there's a recurive field, do update
176 | if (transformer.RecursiveRelationshipField != null)
177 | UpdateRecursiveField(objLoop.ApiName, workingList, transformer.RecursiveRelationshipField);
178 |
179 |
180 | ProgressUpdate(string.Format("Summary for {0}: Success {1} Fail {2}",
181 | objLoop.ApiName, objres.SuccessCount, objres.FailCount));
182 |
183 | }
184 |
185 | // log summary
186 | ProgressUpdate("************************************************");
187 | foreach (var resLoop in res.ObjectResults)
188 | {
189 | ProgressUpdate(string.Format("Summary for {0}: Success {1} Fail {2}",
190 | resLoop.ApiName, resLoop.SuccessCount, resLoop.FailCount));
191 |
192 | }
193 | ProgressUpdate("************************************************");
194 |
195 | return res;
196 | }
197 |
198 |
199 |
200 |
201 |
202 |
203 | private void UpdateRecursiveField(string apiName, List workingList, string recursiveRelationshipField)
204 | {
205 | logger.DebugFormat("Object {0} has a recursive relation field {1}, now doing second pass to set it....",
206 | apiName, recursiveRelationshipField);
207 |
208 | // make a new list of sObjects to do the update
209 | List updateList = new List();
210 | foreach (var wrapLoop in workingList)
211 | {
212 | if (!string.IsNullOrEmpty(wrapLoop.RecursiveRelationshipOriginalId))
213 | {
214 | var upd = new sObject();
215 |
216 | upd.type = wrapLoop.sObj.type;
217 | upd.Id = wrapLoop.NewId;
218 | XmlDocument dummydoc = new XmlDocument();
219 | XmlElement recursiveEl = dummydoc.CreateElement(recursiveRelationshipField);
220 |
221 | string replaceValue = _relationMapper.RecallNewId(apiName, wrapLoop.RecursiveRelationshipOriginalId);
222 |
223 | if (replaceValue == null)
224 | {
225 | logger.DebugFormat("Object {0} {1} recursive field {2} have value {3} could not translate - will ignore",
226 | apiName, wrapLoop.OriginalId, recursiveRelationshipField, wrapLoop.RecursiveRelationshipOriginalId);
227 | }
228 | else
229 | {
230 |
231 | recursiveEl.InnerText = replaceValue;
232 |
233 | upd.Any = new XmlElement[] { recursiveEl };
234 |
235 | updateList.Add(upd);
236 | }
237 | }
238 |
239 | }
240 |
241 | logger.DebugFormat("{0} rows in Object {1} have recursive relation {2} to update ....",
242 | updateList.Count(), apiName, recursiveRelationshipField);
243 |
244 | // update objects in batches
245 | int successCount = 0;
246 | int failCount = 0;
247 | int done = 0;
248 | bool allDone = false;
249 | if (updateList.Count == 0)
250 | allDone = true;
251 | while (!allDone)
252 | {
253 | var batch = updateList.Skip(done).Take(100).ToList();
254 | done += batch.Count;
255 | if (done >= updateList.Count)
256 | allDone = true;
257 |
258 | var updateRes = _targetTasks.UpdateSObjects(apiName,
259 | batch.ToArray());
260 |
261 | for (int i = 0; i < updateRes.Length; i++)
262 | {
263 | if (updateRes[i].Success)
264 | {
265 | successCount+=1;
266 | }
267 | else
268 | {
269 |
270 | logger.WarnFormat("Error when updating {0} {1} in target: {2}",
271 | apiName, batch[i].Id, updateRes[i].ErrorMessage);
272 | failCount += 1;
273 | }
274 |
275 | }
276 |
277 | }
278 | logger.DebugFormat("Object {0} recursive relation {1} updated. Attempted {2} Success {3} Failed {4}",
279 | apiName, recursiveRelationshipField, updateList.Count, successCount, failCount);
280 |
281 | }
282 |
283 | private void LoginToBoth()
284 | {
285 |
286 | try
287 | {
288 | _sourceTasks.LoginIfRequired();
289 |
290 | }
291 | catch (Exception e)
292 | {
293 | string newMess = string.Format("Error while logging in to Source: {0}",
294 | e.Message);
295 | throw new ApplicationException(newMess, e);
296 | }
297 |
298 | try
299 | {
300 | _targetTasks.LoginIfRequired();
301 |
302 | }
303 | catch (Exception e)
304 | {
305 | string newMess = string.Format("Error while logging in to Target: {0}",
306 | e.Message);
307 | throw new ApplicationException(newMess, e);
308 | }
309 | }
310 |
311 | public void DeleteTargetData()
312 | {
313 | this.DeleteTargetData(null, false);
314 | }
315 |
316 | public void DeleteTargetData(IProgress progress, bool ignoreFilters)
317 | {
318 | _progress = progress;
319 | ProgressUpdate("Logging into Target ...");
320 | _targetTasks.LoginIfRequired();
321 | var reverseObjects = _instructions.SbbObjects.AsEnumerable().Reverse();
322 |
323 | foreach (SbbObject objLoop in reverseObjects)
324 | {
325 | String filter = objLoop.Filter;
326 | String filterInfo = null;
327 | if (filter == null)
328 | filterInfo = "No filter specified in instruction file";
329 | else
330 | filterInfo = "Filter in instruction file = " + filter;
331 |
332 | if (ignoreFilters && filter != null)
333 | {
334 | filterInfo = "Filter from instruction file bypassed due to ignoreFilters flag";
335 | filter = null;
336 | }
337 | ProgressUpdate(string.Format("Starting deletion for {0}, filter: {1}", objLoop.ApiName, filterInfo));
338 |
339 |
340 | var targetIds = _targetTasks.GetIdsFromSObject(objLoop.ApiName, filter);
341 | ProgressUpdate(string.Format("Received {0} {1} ids from target", targetIds.Count, objLoop.ApiName));
342 | int done = 0;
343 | bool allDone = false;
344 | if (targetIds.Count == 0)
345 | allDone = true;
346 | while (!allDone)
347 | {
348 | string[] idarray = targetIds.Skip(done).Take(100).ToArray();
349 | done += idarray.Length;
350 | if (done >= targetIds.Count)
351 | allDone = true;
352 | _targetTasks.DeleteSObjects(objLoop.ApiName, idarray);
353 |
354 | }
355 | ProgressUpdate(string.Format("Deleted {0} {1} records from target", targetIds.Count, objLoop.ApiName));
356 |
357 | }
358 | }
359 |
360 | }
361 | }
362 |
--------------------------------------------------------------------------------
/SandboxberryLib/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | // SandboxBerry - tool for copying test data into Salesforce sandboxes
2 | // Copyright (C) 2017 Ian Finch
3 | //
4 | // This program is free software; you can redistribute it and/or
5 | // modify it under the terms of the GNU General Public License
6 | // as published by the Free Software Foundation; either version 2
7 | // of the License, or (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program; if not, write to the Free Software
16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 |
18 | using System.Reflection;
19 | using System.Runtime.CompilerServices;
20 | using System.Runtime.InteropServices;
21 |
22 | // General Information about an assembly is controlled through the following
23 | // set of attributes. Change these attribute values to modify the information
24 | // associated with an assembly.
25 | [assembly: AssemblyTitle("SandboxberryLib")]
26 | [assembly: AssemblyDescription("")]
27 | [assembly: AssemblyConfiguration("")]
28 | [assembly: AssemblyCompany("")]
29 | [assembly: AssemblyProduct("SandboxberryLib")]
30 | [assembly: AssemblyCopyright("Copyright © 2017")]
31 | [assembly: AssemblyTrademark("")]
32 | [assembly: AssemblyCulture("")]
33 |
34 | // Setting ComVisible to false makes the types in this assembly not visible
35 | // to COM components. If you need to access a type in this assembly from
36 | // COM, set the ComVisible attribute to true on that type.
37 | [assembly: ComVisible(false)]
38 |
39 | // The following GUID is for the ID of the typelib if this project is exposed to COM
40 | [assembly: Guid("d626b87b-bc27-4bc3-98ef-8abc4ec4c9f5")]
41 |
42 | // Version information for an assembly consists of the following four values:
43 | //
44 | // Major Version
45 | // Minor Version
46 | // Build Number
47 | // Revision
48 | //
49 | // You can specify all the values or you can default the Build and Revision Numbers
50 | // by using the '*' as shown below:
51 | // [assembly: AssemblyVersion("1.0.*")]
52 | [assembly: AssemblyVersion("1.3.0.0")]
53 | [assembly: AssemblyFileVersion("1.3.0.0")]
54 |
--------------------------------------------------------------------------------
/SandboxberryLib/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.34014
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace SandboxberryLib.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 |
26 | [global::System.Configuration.ApplicationScopedSettingAttribute()]
27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
28 | [global::System.Configuration.SpecialSettingAttribute(global::System.Configuration.SpecialSetting.WebServiceUrl)]
29 | [global::System.Configuration.DefaultSettingValueAttribute("https://test.salesforce.com/services/Soap/u/32.0")]
30 | public string SandboxberryLib_SalesforcePartnerApi_SforceService {
31 | get {
32 | return ((string)(this["SandboxberryLib_SalesforcePartnerApi_SforceService"]));
33 | }
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/SandboxberryLib/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | https://test.salesforce.com/services/Soap/u/32.0
7 |
8 |
9 |
--------------------------------------------------------------------------------
/SandboxberryLib/RelationMapper.cs:
--------------------------------------------------------------------------------
1 | // SandboxBerry - tool for copying test data into Salesforce sandboxes
2 | // Copyright (C) 2017 Ian Finch
3 | //
4 | // This program is free software; you can redistribute it and/or
5 | // modify it under the terms of the GNU General Public License
6 | // as published by the Free Software Foundation; either version 2
7 | // of the License, or (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program; if not, write to the Free Software
16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 |
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Linq;
21 | using System.Text;
22 | using System.Threading.Tasks;
23 | using log4net;
24 |
25 | namespace SandboxberryLib
26 | {
27 | public class RelationMapper
28 | {
29 | private static readonly ILog logger = LogManager.GetLogger(typeof(RelationMapper));
30 |
31 |
32 | private Dictionary> _idMap;
33 |
34 | public RelationMapper()
35 | {
36 | _idMap = new Dictionary>();
37 | }
38 |
39 | public void Remember(string apiName, string originalId, string newId)
40 | {
41 | if (!_idMap.ContainsKey(apiName))
42 | _idMap.Add(apiName, new Dictionary());
43 |
44 | var objDict = _idMap[apiName];
45 |
46 | if (!objDict.ContainsKey(originalId))
47 | objDict.Add(originalId, newId);
48 |
49 |
50 | }
51 |
52 | public string RecallNewId(string apiName, string originalId)
53 | {
54 | if (!_idMap.ContainsKey(apiName))
55 | {
56 | logger.DebugFormat("RecallNewId: no ids mapped for object {0}", apiName);
57 | return null;
58 | }
59 |
60 | var objDict = _idMap[apiName];
61 |
62 | if (!objDict.ContainsKey(originalId))
63 | {
64 | logger.DebugFormat("RecallNewId: object {0} {1} does not have a newId saved in the map",
65 | apiName, originalId);
66 | return null;
67 | }
68 |
69 | return objDict[originalId];
70 | }
71 |
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/SandboxberryLib/Resources/SbbInstructionSetSchema.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/SandboxberryLib/ResultsModel/PopulateObjectResult.cs:
--------------------------------------------------------------------------------
1 | // SandboxBerry - tool for copying test data into Salesforce sandboxes
2 | // Copyright (C) 2017 Ian Finch
3 | //
4 | // This program is free software; you can redistribute it and/or
5 | // modify it under the terms of the GNU General Public License
6 | // as published by the Free Software Foundation; either version 2
7 | // of the License, or (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program; if not, write to the Free Software
16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 |
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Linq;
21 | using System.Text;
22 | using System.Threading.Tasks;
23 |
24 | namespace SandboxberryLib.ResultsModel
25 | {
26 | public class PopulateObjectResult
27 | {
28 | public PopulateObjectResult()
29 | {
30 | RowFailInfoList = new List();
31 | }
32 |
33 | public string ApiName { get; set; }
34 | public int SourceRows { get; set; }
35 | public int SuccessCount { get; set; }
36 | public int FailCount { get; set; }
37 |
38 | public List RowFailInfoList { get; set; }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/SandboxberryLib/ResultsModel/PopulateSandboxResult.cs:
--------------------------------------------------------------------------------
1 | // SandboxBerry - tool for copying test data into Salesforce sandboxes
2 | // Copyright (C) 2017 Ian Finch
3 | //
4 | // This program is free software; you can redistribute it and/or
5 | // modify it under the terms of the GNU General Public License
6 | // as published by the Free Software Foundation; either version 2
7 | // of the License, or (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program; if not, write to the Free Software
16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 |
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Linq;
21 | using System.Text;
22 | using System.Threading.Tasks;
23 |
24 | namespace SandboxberryLib.ResultsModel
25 | {
26 | public class PopulateSandboxResult
27 | {
28 | public PopulateSandboxResult()
29 | {
30 | ObjectResults = new List();
31 | }
32 |
33 | public List ObjectResults { get; set; }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/SandboxberryLib/ResultsModel/RowFailInfo.cs:
--------------------------------------------------------------------------------
1 | // SandboxBerry - tool for copying test data into Salesforce sandboxes
2 | // Copyright (C) 2017 Ian Finch
3 | //
4 | // This program is free software; you can redistribute it and/or
5 | // modify it under the terms of the GNU General Public License
6 | // as published by the Free Software Foundation; either version 2
7 | // of the License, or (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program; if not, write to the Free Software
16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 |
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Linq;
21 | using System.Text;
22 | using System.Threading.Tasks;
23 |
24 | namespace SandboxberryLib.ResultsModel
25 | {
26 | public class RowFailInfo
27 | {
28 | public string ApiName { get; set; }
29 | public string SourceId { get; set; }
30 | public string ErrorMessage { get; set; }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/SandboxberryLib/SalesforceSession.cs:
--------------------------------------------------------------------------------
1 | // SandboxBerry - tool for copying test data into Salesforce sandboxes
2 | // Copyright (C) 2017 Ian Finch
3 | //
4 | // This program is free software; you can redistribute it and/or
5 | // modify it under the terms of the GNU General Public License
6 | // as published by the Free Software Foundation; either version 2
7 | // of the License, or (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program; if not, write to the Free Software
16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 |
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Linq;
21 | using System.Text;
22 | using System.Threading.Tasks;
23 | using log4net;
24 | using System.Configuration;
25 | using System.Web.Services;
26 |
27 | using SandboxberryLib.SalesforcePartnerApi;
28 | using System.Web.Services.Protocols;
29 | using SandboxberryLib.InstructionsModel;
30 | using System.Net;
31 |
32 | namespace SandboxberryLib
33 | {
34 | public class SalesforceSession
35 | {
36 | private static readonly ILog logger = LogManager.GetLogger(typeof(SalesforceSession));
37 |
38 | private SbbCredentials _credentials;
39 |
40 | public SalesforceSession(SbbCredentials cred)
41 | {
42 | _credentials = cred;
43 | // set up for TLS1.2 or TLS1.1 but not TLS1.0
44 | System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11;
45 | }
46 |
47 | public SforceService Login()
48 | {
49 |
50 | SforceService service = new SforceService();
51 | service.Url = _credentials.SalesforceUrl;
52 |
53 |
54 | LoginResult loginResult;
55 | try
56 | {
57 | loginResult = service.login(_credentials.SalesforceLogin, _credentials.SalesforcePassword);
58 | }
59 | catch (SoapException ex)
60 | {
61 | logger.Error(string.Format("error during attempted login for {0}", _credentials.SalesforceLogin), ex);
62 | throw ex;
63 |
64 | }
65 |
66 | /**
67 | * Once the client application has logged in successfully, it will use
68 | * the results of the login call to reset the endpoint of the service
69 | * to the virtual server instance that is servicing your organization
70 | */
71 | service.Url = loginResult.serverUrl;
72 |
73 | /**
74 | * The client application now has an instance of the SforceService
75 | * that is pointing to the correct endpoint. Next, the sample client
76 | * application sets a persistent SOAP header (to be included on all
77 | * subsequent calls that are made with SforceService) that contains the
78 | * valid sessionId for our login credentials. To do this, the
79 | * client application creates a new SessionHeader object and persists it to
80 | * the SforceService. Add the session ID returned from the login to the
81 | * session header.
82 | */
83 | service.SessionHeaderValue = new SessionHeader();
84 | service.SessionHeaderValue.sessionId = loginResult.sessionId;
85 |
86 | logger.DebugFormat("Successful login for {0}", _credentials.SalesforceLogin);
87 |
88 | return service;
89 | }
90 |
91 | // like login, but doesn't return anything
92 | public void TestLogin()
93 | {
94 | var dummy = this.Login();
95 |
96 | }
97 |
98 | public bool AllowDeletion()
99 | {
100 | bool allowDelete = false;
101 | if (_credentials.SalesforceUrl.ToLower().StartsWith("https://test.salesforce.com"))
102 | allowDelete = true;
103 | return allowDelete;
104 | }
105 |
106 |
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/SandboxberryLib/SalesforceTasks.cs:
--------------------------------------------------------------------------------
1 | // SandboxBerry - tool for copying test data into Salesforce sandboxes
2 | // Copyright (C) 2017 Ian Finch
3 | //
4 | // This program is free software; you can redistribute it and/or
5 | // modify it under the terms of the GNU General Public License
6 | // as published by the Free Software Foundation; either version 2
7 | // of the License, or (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program; if not, write to the Free Software
16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 |
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Linq;
21 | using System.Text;
22 | using System.Threading.Tasks;
23 | using SandboxberryLib.SalesforcePartnerApi;
24 | using SandboxberryLib.InstructionsModel;
25 | using log4net;
26 |
27 | namespace SandboxberryLib
28 | {
29 | public class SalesforceTasks
30 | {
31 |
32 | private static readonly ILog logger = LogManager.GetLogger(typeof(SalesforceTasks));
33 |
34 | private SalesforceSession _salesforceSession;
35 | private SforceService _binding = null;
36 |
37 | private Dictionary _metaDictionary;
38 |
39 | public SalesforceTasks(SbbCredentials cred)
40 | : this(new SalesforceSession(cred))
41 | { }
42 |
43 | public SalesforceTasks(SalesforceSession sesh)
44 | {
45 | _salesforceSession = sesh;
46 | _metaDictionary = new Dictionary();
47 |
48 | }
49 |
50 |
51 | public void FetchObjectMetadata(string[] apiNameArray)
52 | {
53 | LoginIfRequired();
54 | logger.DebugFormat("Fetching metadata for {0} object types", apiNameArray.Length);
55 | var metaList = _binding.describeSObjects(apiNameArray);
56 |
57 | foreach (var metaLoop in metaList)
58 | {
59 | if (!_metaDictionary.ContainsKey(metaLoop.name))
60 | _metaDictionary.Add(metaLoop.name, metaLoop);
61 |
62 | }
63 |
64 | }
65 |
66 | public DescribeSObjectResult GetObjectMeta(string apiName)
67 | {
68 | if (!_metaDictionary.ContainsKey(apiName))
69 | {
70 | logger.DebugFormat("metadata for {0} needed, sending request to salesforce api...", apiName);
71 | FetchObjectMetadata(new string[] { apiName });
72 | }
73 | if (!_metaDictionary.ContainsKey(apiName))
74 | throw new ApplicationException(string.Format("Could not return metadata for type {0}", apiName));
75 | return _metaDictionary[apiName];
76 | }
77 |
78 | public Dictionary GetObjectRelationships(string apiName)
79 | {
80 | var res = new Dictionary();
81 | var meta = GetObjectMeta(apiName);
82 | var fieldsWeUse = RemoveSystemColumns(GetObjectColumns(apiName));
83 |
84 | var relationshipFields = meta.fields.Where(f => f.relationshipName != null);
85 | foreach (var fieldLoop in relationshipFields)
86 | {
87 | if (fieldsWeUse.Contains(fieldLoop.name))
88 | {
89 | if (fieldLoop.referenceTo == null || fieldLoop.referenceTo.Length == 0)
90 | {
91 | logger.DebugFormat("GetObjectRelationships: {0} {1} does not specify referenceTo type so ignoring",
92 | apiName, fieldLoop.name);
93 | }
94 | else if (fieldLoop.referenceTo.Length > 1)
95 | {
96 | logger.DebugFormat("GetObjectRelationships: {0} {1} refers to multiple types {2} so ignoring",
97 | apiName, fieldLoop.name, string.Join(", ", fieldLoop.referenceTo));
98 | }
99 | else
100 | {
101 | var fieldName = fieldLoop.name;
102 | var destinationObject = fieldLoop.referenceTo[0];
103 | if (destinationObject == "RecordType")
104 | logger.DebugFormat("GetObjectRelationships: {0} {1} refers to {2} so ignoring",
105 | apiName, fieldLoop.name, destinationObject);
106 | else
107 | res.Add(fieldName, destinationObject);
108 | }
109 | }
110 | else
111 | logger.DebugFormat("GetObjectRelationships: {0} ignore field {1} because out of scope",
112 | apiName, fieldLoop.name);
113 |
114 | }
115 | logger.DebugFormat("GetObjectRelationships: returning {0} relationships for {1}",
116 | res.Count, apiName);
117 | if (logger.IsDebugEnabled)
118 | {
119 | foreach (string keyLoop in res.Keys)
120 | {
121 | logger.DebugFormat("GetObjectRelationships: returning {0} {1} relationship to {2}",
122 | apiName, keyLoop, res[keyLoop]);
123 | }
124 | }
125 | return res;
126 | }
127 |
128 | public List GetObjectColumns(string objName)
129 | {
130 |
131 | var meta = GetObjectMeta(objName);
132 | List fieldNames = meta.fields.Where(f => f.autoNumber == false && f.calculated == false && f.type != fieldType.address && (f.createable == true || f.name == "Id")).Select(f => f.name).ToList();
133 |
134 | return fieldNames;
135 |
136 | }
137 |
138 | public List RemoveSystemColumns(List colNameList)
139 | {
140 | List unwantedCols = new string[] {
141 | "IsDeleted",
142 | "CreatedDate",
143 | "CreatedById",
144 | "LastModifiedDate",
145 | "LastModifiedById",
146 | "SystemModstamp",
147 | "LastViewedDate",
148 | "LastReferencedDate"}.ToList();
149 | return colNameList.Except(unwantedCols).ToList();
150 | }
151 |
152 | public void LoginIfRequired()
153 | {
154 | if (_binding == null)
155 | _binding = _salesforceSession.Login();
156 |
157 | }
158 |
159 | public string BuildQuery(string sobjectName, List colList, string filter)
160 | {
161 | StringBuilder sb = new StringBuilder();
162 | sb.AppendFormat("select {0} from {1}",
163 | String.Join(", ", colList), sobjectName);
164 | if (!string.IsNullOrEmpty(filter))
165 | sb.AppendFormat(" where {0}", filter);
166 | return sb.ToString();
167 | }
168 |
169 | public List GetDataFromSObject(string sobjectName, string filter)
170 | {
171 | LoginIfRequired();
172 | List colNames = RemoveSystemColumns(GetObjectColumns(sobjectName));
173 | string soql = BuildQuery(sobjectName, colNames, filter);
174 |
175 | bool allResultsReturned = false;
176 | List allResults = new List();
177 | QueryResult qr = _binding.query(soql);
178 | if (qr.size > 0)
179 | {
180 | while (!allResultsReturned)
181 | {
182 | allResults.AddRange(qr.records);
183 | if (qr.done)
184 | allResultsReturned = true;
185 | else
186 | qr = _binding.queryMore(qr.queryLocator);
187 | }
188 | }
189 |
190 | return allResults;
191 | }
192 |
193 | public List GetIdsFromSObject(string sobjectName, string filter)
194 | {
195 | LoginIfRequired();
196 |
197 | string soql = BuildQuery(sobjectName, new string[] {"Id"}.ToList(), filter);
198 |
199 | List allResults = FetchQueryDataIdOnly(soql);
200 |
201 | return allResults;
202 | }
203 |
204 | private List FetchQueryDataIdOnly(string soql)
205 | {
206 | bool allResultsReturned = false;
207 | List allResults = new List();
208 | QueryResult qr = _binding.query(soql);
209 | if (qr.size > 0)
210 | {
211 | while (!allResultsReturned)
212 | {
213 | allResults.AddRange(qr.records.Select(s => s.Id));
214 | if (qr.done)
215 | allResultsReturned = true;
216 | else
217 | qr = _binding.queryMore(qr.queryLocator);
218 | }
219 | }
220 | return allResults;
221 | }
222 |
223 | public string InsertSObject(string sobjectName, sObject obj)
224 | {
225 |
226 | LoginIfRequired();
227 | sObject[] objArray = new sObject[]{ obj};
228 | var saveResults = _binding.create(objArray);
229 |
230 | CheckSaveResults(saveResults, string.Format("Creation of {0}", sobjectName), true);
231 |
232 | if (saveResults.Length != 1)
233 | throw new ApplicationException(string.Format("Expected one saveresult back for creation of {0} but got {1}",
234 | sobjectName, saveResults.Length));
235 |
236 | var rowResult = saveResults[0];
237 |
238 |
239 | return rowResult.id;
240 | }
241 |
242 | public InsertSObjectsResult[] InsertSObjects(string sobjectName, sObject[] objArray)
243 | {
244 |
245 | LoginIfRequired();
246 | var res = new InsertSObjectsResult[objArray.Length];
247 | var saveResults = _binding.create(objArray);
248 |
249 | if (saveResults.Length != objArray.Length)
250 | throw new ApplicationException(string.Format("Sent {0} objects to create api call but got {1} results back. Numbers should match.",
251 | objArray.Length, saveResults.Length));
252 | for (int i = 0; i < saveResults.Length; i++)
253 | {
254 | res[i] = new InsertSObjectsResult();
255 | if (saveResults[i].success)
256 | res[i].NewId = saveResults[i].id;
257 | else
258 | res[i].ErrorMessage = GetSaveResultErrorText(saveResults[i]);
259 |
260 | }
261 |
262 | return res;
263 | }
264 |
265 | public UpdateSObjectsResult[] UpdateSObjects(string sobjectName, sObject[] objArray)
266 | {
267 |
268 | LoginIfRequired();
269 | var res = new UpdateSObjectsResult[objArray.Length];
270 | var saveResults = _binding.update(objArray);
271 |
272 | if (saveResults.Length != objArray.Length)
273 | throw new ApplicationException(string.Format("Sent {0} objects to update api call but got {1} results back. Numbers should match.",
274 | objArray.Length, saveResults.Length));
275 | for (int i = 0; i < saveResults.Length; i++)
276 | {
277 | res[i] = new UpdateSObjectsResult();
278 | if (saveResults[i].success)
279 | res[i].Success = true;
280 | else
281 | res[i].ErrorMessage = GetSaveResultErrorText(saveResults[i]);
282 |
283 | }
284 |
285 | return res;
286 | }
287 |
288 |
289 | public class InsertSObjectsResult
290 | {
291 | public string NewId { get; set; }
292 | public string ErrorMessage { get; set; }
293 | }
294 |
295 | public class UpdateSObjectsResult
296 | {
297 | public bool Success { get; set; }
298 | public string ErrorMessage { get; set; }
299 | }
300 |
301 | public void DeleteSObjects(string sobjectName, string[] idarray)
302 | {
303 | LoginIfRequired();
304 |
305 | if (!_salesforceSession.AllowDeletion())
306 | {
307 | throw new ApplicationException("This app will not allow deletion to be run on target database");
308 | }
309 |
310 | var deleteResults = _binding.delete(idarray);
311 |
312 | int successCount = 0;
313 | int errorCount = 0;
314 | List errorMessages = new List();
315 | foreach (DeleteResult resLoop in deleteResults)
316 | {
317 | if (resLoop.success)
318 | successCount += 1;
319 | else
320 | {
321 | errorCount += 1;
322 | string errMess = string.Format("delete of {0} {1} failed message {2}",
323 | sobjectName, resLoop.id, string.Join(", ", resLoop.errors.Select(e => e.message)));
324 | logger.DebugFormat(errMess);
325 | errorMessages.Add(errMess);
326 | }
327 | }
328 | logger.DebugFormat("deletion of {0} - {1} success {2} failed",
329 | sobjectName, successCount, errorCount);
330 | if (errorCount>0)
331 | throw new ApplicationException(string.Format("deletion of {0} - {1} failed {2}",
332 | sobjectName, errorCount, string.Join(", ", errorMessages)));
333 |
334 |
335 | }
336 |
337 |
338 |
339 | public List GetInactiveUsers()
340 | {
341 | LoginIfRequired();
342 | string soql = "Select id from user where isActive=False";
343 | return FetchQueryDataIdOnly(soql);
344 | }
345 |
346 | public List GetAllUsers()
347 | {
348 | LoginIfRequired();
349 | string soql = "Select id from user";
350 | return FetchQueryDataIdOnly(soql);
351 | }
352 |
353 | public string GetCurrentUserId()
354 | {
355 | LoginIfRequired();
356 | return _binding.getUserInfo().userId;
357 | }
358 |
359 | public bool CheckSaveResults(SaveResult[] saveResults, string contextForLog, bool throwError)
360 | {
361 | bool allOK = true;
362 | List errorSummaries = new List();
363 | foreach (SaveResult srLoop in saveResults)
364 | {
365 | if (!srLoop.success)
366 | {
367 | allOK = false;
368 | string saveResultErr = GetSaveResultErrorText(srLoop);
369 |
370 | string errMess = string.Format("Salesforce Save failed, Context {0}, Errors {1}",
371 | contextForLog, saveResultErr);
372 | logger.WarnFormat(errMess);
373 | errorSummaries.Add(errMess);
374 | }
375 | }
376 | if (!allOK && throwError)
377 | throw new ApplicationException(string.Join(", ", errorSummaries));
378 | return allOK;
379 | }
380 |
381 | private string GetSaveResultErrorText(SaveResult saveResult)
382 | {
383 | StringBuilder sb = new StringBuilder();
384 | foreach (var eloop in saveResult.errors)
385 | {
386 | if (sb.Length > 0)
387 | sb.Append(", ");
388 | sb.AppendFormat("Error {0} Status Code {1} ", eloop.message, eloop.statusCode.ToString());
389 | if (eloop.fields != null)
390 | sb.AppendFormat("Fields {0}", string.Join(",", eloop.fields));
391 | }
392 | return sb.ToString();
393 | }
394 |
395 |
396 | }
397 | }
398 |
--------------------------------------------------------------------------------
/SandboxberryLib/SandboxberryLib.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {2057FF00-1368-40F2-A79A-B2CE6D3CBA77}
8 | Library
9 | Properties
10 | SandboxberryLib
11 | SandboxberryLib
12 | v4.5
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 | ..\packages\log4net.2.0.3\lib\net40-full\log4net.dll
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | True
57 | True
58 | Settings.settings
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | True
68 | True
69 | Reference.map
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | Dynamic
81 | Web References\SalesforcePartnerApi\
82 | D:\Codeulike\Code\SandboxberrySol\SandboxberryLib\SalesforceWsdl\partner.wsdl
83 |
84 |
85 |
86 |
87 | Settings
88 | SandboxberryLib_SalesforcePartnerApi_SforceService
89 |
90 |
91 |
92 |
93 |
94 |
95 | SettingsSingleFileGenerator
96 | Settings.Designer.cs
97 |
98 |
99 | Designer
100 |
101 |
102 | Reference.map
103 |
104 |
105 | Reference.map
106 |
107 |
108 | Reference.map
109 |
110 |
111 | Reference.map
112 |
113 |
114 | Reference.map
115 |
116 |
117 | Reference.map
118 |
119 |
120 | Reference.map
121 |
122 |
123 | Reference.map
124 |
125 |
126 | Reference.map
127 |
128 |
129 | Reference.map
130 |
131 |
132 | Reference.map
133 |
134 |
135 | Reference.map
136 |
137 |
138 | Reference.map
139 |
140 |
141 | Reference.map
142 |
143 |
144 | Reference.map
145 |
146 |
147 | Reference.map
148 |
149 |
150 | Reference.map
151 |
152 |
153 | Reference.map
154 |
155 |
156 | Reference.map
157 |
158 |
159 | Reference.map
160 |
161 |
162 | Reference.map
163 |
164 |
165 | Reference.map
166 |
167 |
168 | Reference.map
169 |
170 |
171 | Reference.map
172 |
173 |
174 | Reference.map
175 |
176 |
177 | Reference.map
178 |
179 |
180 | Reference.map
181 |
182 |
183 | Reference.map
184 |
185 |
186 | Reference.map
187 |
188 |
189 | Reference.map
190 |
191 |
192 | Reference.map
193 |
194 |
195 | Reference.map
196 |
197 |
198 |
199 | Reference.map
200 |
201 |
202 | Reference.map
203 |
204 |
205 | Reference.map
206 |
207 |
208 | Reference.map
209 |
210 |
211 | MSDiscoCodeGenerator
212 | Reference.cs
213 |
214 |
215 | Reference.map
216 |
217 |
218 | Reference.map
219 |
220 |
221 | Reference.map
222 |
223 |
224 | Reference.map
225 |
226 |
227 | Reference.map
228 |
229 |
230 | Reference.map
231 |
232 |
233 | Reference.map
234 |
235 |
236 | Reference.map
237 |
238 |
239 |
240 |
241 |
248 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/DeleteResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.DeleteResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/DescribeAppMenuItem.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.DescribeAppMenuItem, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/DescribeApprovalLayout.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.DescribeApprovalLayout, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/DescribeAvailableQuickActionResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.DescribeAvailableQuickActionResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/DescribeCompactLayout.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.DescribeCompactLayout, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/DescribeCompactLayoutsResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.DescribeCompactLayoutsResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/DescribeDataCategoryGroupResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.DescribeDataCategoryGroupResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/DescribeDataCategoryGroupStructureResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.DescribeDataCategoryGroupStructureResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/DescribeFlexiPageResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.DescribeFlexiPageResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/DescribeGlobalResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.DescribeGlobalResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/DescribeGlobalTheme.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.DescribeGlobalTheme, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/DescribeLayoutResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.DescribeLayoutResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/DescribeQuickActionResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.DescribeQuickActionResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/DescribeSObjectResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.DescribeSObjectResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/DescribeSearchLayoutResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.DescribeSearchLayoutResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/DescribeSearchScopeOrderResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.DescribeSearchScopeOrderResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/DescribeSoftphoneLayoutResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.DescribeSoftphoneLayoutResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/DescribeSoqlListView.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.DescribeSoqlListView, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/DescribeTab.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.DescribeTab, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/DescribeTabSetResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.DescribeTabSetResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/DescribeThemeItem.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.DescribeThemeItem, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/EmptyRecycleBinResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.EmptyRecycleBinResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/ExecuteListViewResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.ExecuteListViewResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/GetDeletedResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.GetDeletedResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/GetServerTimestampResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.GetServerTimestampResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/GetUpdatedResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.GetUpdatedResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/GetUserInfoResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.GetUserInfoResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/InvalidateSessionsResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.InvalidateSessionsResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/KnowledgeSettings.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.KnowledgeSettings, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/LeadConvertResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.LeadConvertResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/LoginResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.LoginResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/MergeResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.MergeResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/PerformQuickActionResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.PerformQuickActionResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/ProcessResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.ProcessResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/QueryResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.QueryResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/QuickActionTemplateResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.QuickActionTemplateResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/Reference.map:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/ResetPasswordResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.ResetPasswordResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/SaveResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.SaveResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/SearchResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.SearchResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/SendEmailResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.SendEmailResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/SetPasswordResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.SetPasswordResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/UndeleteResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.UndeleteResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/UpsertResult.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.UpsertResult, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/Web References/SalesforcePartnerApi/sObject.datasource:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | SandboxberryLib.SalesforcePartnerApi.sObject, Web References.SalesforcePartnerApi.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
10 |
--------------------------------------------------------------------------------
/SandboxberryLib/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
12 | https://test.salesforce.com/services/Soap/u/32.0
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/SandboxberryLib/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/SandboxberryOpenSourceSol.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2012
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SandboxberryLib", "SandboxberryLib\SandboxberryLib.csproj", "{2057FF00-1368-40F2-A79A-B2CE6D3CBA77}"
5 | EndProject
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SandboxberryTests", "SandboxberryTests\SandboxberryTests.csproj", "{64D80534-55D5-44E4-BD5E-A4B88E655788}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{43B276E4-0AAA-46CB-9799-759B2EAFBF56}"
9 | ProjectSection(SolutionItems) = preProject
10 | License_Gpl2.txt = License_Gpl2.txt
11 | notes.txt = notes.txt
12 | EndProjectSection
13 | EndProject
14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sandboxberry", "Sandboxberry\Sandboxberry.csproj", "{108FA37A-1DA5-4189-AF60-167567E149E5}"
15 | EndProject
16 | Global
17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
18 | Debug|Any CPU = Debug|Any CPU
19 | Release|Any CPU = Release|Any CPU
20 | EndGlobalSection
21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
22 | {2057FF00-1368-40F2-A79A-B2CE6D3CBA77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {2057FF00-1368-40F2-A79A-B2CE6D3CBA77}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {2057FF00-1368-40F2-A79A-B2CE6D3CBA77}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {2057FF00-1368-40F2-A79A-B2CE6D3CBA77}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {64D80534-55D5-44E4-BD5E-A4B88E655788}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {64D80534-55D5-44E4-BD5E-A4B88E655788}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {64D80534-55D5-44E4-BD5E-A4B88E655788}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {64D80534-55D5-44E4-BD5E-A4B88E655788}.Release|Any CPU.Build.0 = Release|Any CPU
30 | {108FA37A-1DA5-4189-AF60-167567E149E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {108FA37A-1DA5-4189-AF60-167567E149E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {108FA37A-1DA5-4189-AF60-167567E149E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {108FA37A-1DA5-4189-AF60-167567E149E5}.Release|Any CPU.Build.0 = Release|Any CPU
34 | EndGlobalSection
35 | GlobalSection(SolutionProperties) = preSolution
36 | HideSolutionNode = FALSE
37 | EndGlobalSection
38 | EndGlobal
39 |
--------------------------------------------------------------------------------
/SandboxberryTests/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
15 | https://test.salesforce.com/services/Soap/u/32.0
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/SandboxberryTests/GeneralTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using SandboxberryLib;
4 | using SandboxberryLib.InstructionsModel;
5 | using log4net;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using System.Configuration;
9 | using System.IO;
10 | using System.Reflection;
11 |
12 | namespace SandboxberryTests
13 | {
14 | [TestClass]
15 | public class GeneralTests
16 | {
17 | private static readonly ILog logger = LogManager.GetLogger(typeof(GeneralTests));
18 |
19 |
20 | [TestMethod]
21 | public void CanBuildQuery()
22 | {
23 | List pretendCols = new string[] {
24 | "Id",
25 | "Name",
26 | "Something__c"}.ToList();
27 |
28 | SalesforceTasks tasks = new SalesforceTasks(TestUtils.MakeDummyCredentials());
29 |
30 | var res = tasks.BuildQuery("Madeup__c", pretendCols, null);
31 | Assert.AreEqual(res, "select Id, Name, Something__c from Madeup__c");
32 | }
33 |
34 | [TestMethod]
35 | public void CanBuildQueryWithFilter()
36 | {
37 | List pretendCols = new string[] {
38 | "Id",
39 | "Name",
40 | "Something__c"}.ToList();
41 |
42 | SalesforceTasks tasks = new SalesforceTasks(TestUtils.MakeDummyCredentials());
43 |
44 | var res = tasks.BuildQuery("Madeup__c", pretendCols, "Something__c = 'a'");
45 | Assert.AreEqual(res, "select Id, Name, Something__c from Madeup__c where Something__c = 'a'");
46 | }
47 |
48 | [TestMethod]
49 | public void CanRemoveSystemCols()
50 | {
51 | List pretendCols = new string[] {
52 | "Id",
53 | "Name",
54 | "Something__c",
55 | "IsDeleted",
56 | "CreatedDate",
57 | "CreatedById",
58 | "LastModifiedDate",
59 | "LastModifiedById",
60 | "SystemModstamp",
61 | "LastViewedDate",
62 | "LastReferencedDate",
63 | "SomethingElse__c"}.ToList();
64 |
65 | SalesforceTasks tasks = new SalesforceTasks(TestUtils.MakeDummyCredentials());
66 |
67 | var res = tasks.RemoveSystemColumns(pretendCols);
68 | Assert.AreEqual(res.Count, 4);
69 | Assert.IsTrue(res.Contains("Id"));
70 | Assert.IsTrue(res.Contains("Name"));
71 | Assert.IsTrue(res.Contains("Something__c"));
72 | Assert.IsTrue(res.Contains("SomethingElse__c"));
73 |
74 | }
75 |
76 | [TestMethod]
77 | public void CanSerializeInstructions()
78 | {
79 |
80 | string[] tables = {"Country__c","Nationality__c",
81 | "Account", "Client__c" };
82 |
83 |
84 | SbbInstructionSet inst = TestUtils.MakeInstructionSet(tables.ToList());
85 | inst.SbbObjects.First(o => o.ApiName == "Account").Filter = "Help_Sandbox_Data_Set__c = true";
86 | inst.SbbObjects.First(o => o.ApiName == "Client__c").Filter = "account__r.Help_Sandbox_Data_Set__c = true";
87 |
88 |
89 | var baseDir = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
90 | var testFile = System.IO.Path.Combine(baseDir, "testinstructions.xml");
91 |
92 | SbbInstructionSet.SaveToFile(testFile, inst);
93 | }
94 |
95 | [TestMethod]
96 | public void GetManfiestResourceNames()
97 | {
98 | Assembly dll = Assembly.GetAssembly(typeof(SbbInstructionSet));
99 | var names = dll.GetManifestResourceNames();
100 | foreach (var n in names)
101 | logger.DebugFormat("Resource: {0}", n);
102 |
103 |
104 | }
105 |
106 |
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/SandboxberryTests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | // SandboxBerry - tool for copying test data into Salesforce sandboxes
2 | // Copyright (C) 2017 Ian Finch
3 | //
4 | // This program is free software; you can redistribute it and/or
5 | // modify it under the terms of the GNU General Public License
6 | // as published by the Free Software Foundation; either version 2
7 | // of the License, or (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program; if not, write to the Free Software
16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 |
18 | using System.Reflection;
19 | using System.Runtime.CompilerServices;
20 | using System.Runtime.InteropServices;
21 |
22 | // General Information about an assembly is controlled through the following
23 | // set of attributes. Change these attribute values to modify the information
24 | // associated with an assembly.
25 | [assembly: AssemblyTitle("SandboxberryTests")]
26 | [assembly: AssemblyDescription("")]
27 | [assembly: AssemblyConfiguration("")]
28 | [assembly: AssemblyCompany("")]
29 | [assembly: AssemblyProduct("SandboxberryTests")]
30 | [assembly: AssemblyCopyright("Copyright © 2014")]
31 | [assembly: AssemblyTrademark("")]
32 | [assembly: AssemblyCulture("")]
33 |
34 | // Setting ComVisible to false makes the types in this assembly not visible
35 | // to COM components. If you need to access a type in this assembly from
36 | // COM, set the ComVisible attribute to true on that type.
37 | [assembly: ComVisible(false)]
38 |
39 | // The following GUID is for the ID of the typelib if this project is exposed to COM
40 | [assembly: Guid("01548f38-60ec-444e-bf2f-2043551a72b8")]
41 |
42 | // Version information for an assembly consists of the following four values:
43 | //
44 | // Major Version
45 | // Minor Version
46 | // Build Number
47 | // Revision
48 | //
49 | // You can specify all the values or you can default the Build and Revision Numbers
50 | // by using the '*' as shown below:
51 | // [assembly: AssemblyVersion("1.0.*")]
52 | [assembly: AssemblyVersion("1.0.0.0")]
53 | [assembly: AssemblyFileVersion("1.0.0.0")]
54 |
55 | [assembly: log4net.Config.XmlConfigurator(ConfigFile = "logging.config", Watch = true)]
56 |
--------------------------------------------------------------------------------
/SandboxberryTests/SandboxberryTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | {64D80534-55D5-44E4-BD5E-A4B88E655788}
7 | Library
8 | Properties
9 | SandboxberryTests
10 | SandboxberryTests
11 | v4.5
12 | 512
13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 10.0
15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
17 | False
18 | UnitTest
19 |
20 |
21 | true
22 | full
23 | false
24 | bin\Debug\
25 | DEBUG;TRACE
26 | prompt
27 | 4
28 |
29 |
30 | pdbonly
31 | true
32 | bin\Release\
33 | TRACE
34 | prompt
35 | 4
36 |
37 |
38 |
39 | ..\packages\log4net.2.0.3\lib\net40-full\log4net.dll
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | Designer
66 |
67 |
68 | Always
69 |
70 |
71 |
72 |
73 |
74 | {2057ff00-1368-40f2-a79a-b2ce6d3cba77}
75 | SandboxberryLib
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | False
86 |
87 |
88 | False
89 |
90 |
91 | False
92 |
93 |
94 | False
95 |
96 |
97 |
98 |
99 |
100 |
101 |
108 |
--------------------------------------------------------------------------------
/SandboxberryTests/TestUtils.cs:
--------------------------------------------------------------------------------
1 | // SandboxBerry - tool for copying test data into Salesforce sandboxes
2 | // Copyright (C) 2017 Ian Finch
3 | //
4 | // This program is free software; you can redistribute it and/or
5 | // modify it under the terms of the GNU General Public License
6 | // as published by the Free Software Foundation; either version 2
7 | // of the License, or (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program; if not, write to the Free Software
16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 |
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Linq;
21 | using System.Text;
22 | using System.Threading.Tasks;
23 | using SandboxberryLib;
24 | using SandboxberryLib.InstructionsModel;
25 | using log4net;
26 | using System.Configuration;
27 |
28 | namespace SandboxberryTests
29 | {
30 | public class TestUtils
31 | {
32 |
33 | // fake credentials for tests
34 | public static SbbCredentials MakeDummyCredentials()
35 | {
36 | var res = new SbbCredentials();
37 | res.SalesforceUrl = "https://test.salesforce.com/services/Soap/u/32.0";
38 | res.SalesforceLogin = "madeup@example.com.sandbox";
39 | res.SalesforcePassword = "passwordAndSecurityToken";
40 | return res;
41 | }
42 |
43 | public static SbbInstructionSet MakeInstructionSet(List objNames)
44 | {
45 | var ret = new SbbInstructionSet();
46 | ret.SourceCredentials = MakeDummyCredentials();
47 | ret.TargetCredentuals = MakeDummyCredentials();
48 | ret.SbbObjects = new List();
49 | foreach (string nameLoop in objNames)
50 | {
51 | var o = new SbbObject();
52 | o.ApiName = nameLoop;
53 | ret.SbbObjects.Add(o);
54 | }
55 | return ret;
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/SandboxberryTests/logging.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/SandboxberryTests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/notes.txt:
--------------------------------------------------------------------------------
1 |
2 | VS bug leads to problems with Partner WSDL v 32
3 | fix here:
4 | https://developer.salesforce.com/forums/ForumsMain?id=906F0000000Ai2JIAS
5 | basically:
6 | In Reference.cs
7 | search and replace
8 | ListViewRecordColumn[][]
9 | and replace it with
10 | ListViewRecordColumn[]
11 |
12 | To generate Schema:
13 | xsd SandboxberryLib.dll /type:SbbInstructionSet
14 |
15 |
16 |
17 |
18 | icon from icons8
19 | http://icons8.com/license/
20 |
--------------------------------------------------------------------------------