TYPO3: How to display Frontendgroup memberships in backend, felogin Extension - typo3

I have a TYPO3 v10 instance. The felogin Extension is installed to manage 4000 users in 100 usergroups, lots of tiny projects.
Is there a feature, a trick, an extension to answer this question, while working in the backend:
For a given frontenduser-group what are the feusers that belong to that group?
There does not seem to be a way to display this in the backend. At least not in the "List" module, after clicking on any frontendgroup-name, then working in any of the standard tabs "
General / Options / Access / Notes / Extended"
Right now I get along with SQL statements like
SELECT * FROM fe_users WHERE usergroup like '%261%';
but this is very inconvenient.
I have migrated the users and groups from one old TYPO3 instance to a newer one, and now I want to enable editors to cross-check and review group memberships themselves.
The Stackoverflow "Similar questions" text-analysis tool points out that my question is indeed similar to this one: Extbase fe_user findByUsergroup - but that question is 4 Years old, and perhaps there has been some progress?

I know of such "included" feature. The listview offers a "ref" (references) column which shows you all references to this group. this might help a bit. but contains pages, content elements... and user records in a mix.
Another option is the export a CSV of the website users with the "Groups, column enabled. This should give them all the data to review the group memberships.
If that is not enough, I would create an custom module to create such a view.

Meanwhile, as a workaround, I have used a nonstandard-SQL feature, the group_concat() function, to copy all frontendusernames of each group into the (empty) "description" field of the fe_groups table.
There they form a comma-separated list. A screenshot illustrates what my backend panel now looks like. See first line:
This method is only feasible of you are running a one-off migration, or if you can practice on a staging server first. You need to have absolute control over the TYPO3 database, and your bosses and editors shouldn't mind and like the final result. Also it overwrites what is in the description column.
Also, frontendusers who are in two or more groups will NOT get added to the csv-lists! Because their usergroupcolumn has values like 262,398 which cannot be INNER JOINed properly with fe_group.uid.
The key benefit of the group_concat() method is that a single SQL UPDATE statement (almost) solves the problem. No custom PHP programming needed.
/* works on mariadb:10.3 */
UPDATE
fe_groups g,
(
SELECT
usergroup,
GROUP_CONCAT(
u.username
ORDER BY
username SEPARATOR ', '
) AS 'usernames'
from
fe_users u
where
usergroup not like '%,%'
group by
usergroup
) AS user_lookup
SET
g.description = user_lookup.usernames
WHERE
user_lookup.usergroup = g.uid
and user_lookup.usergroup not like '%,%';
The code above does not work on mysql 5.7. There I had to try this instead:
/* works on mysql 5-7 */
SET
session group_concat_max_len = 15000;
create temporary table fe_groups_extrainfo
SELECT
usergroup,
GROUP_CONCAT(
u.username
ORDER BY
username SEPARATOR ', '
) AS 'usernames'
from
fe_users u
where
usergroup not like '%,% and uid > 9'
group by
usergroup
limit
0;
insert into
fe_groups_extrainfo
SELECT
usergroup,
GROUP_CONCAT(
u.username
ORDER BY
username SEPARATOR ', '
) AS 'usernames'
from
fe_users u
where
usergroup not like '%,%'
group by
usergroup;
update
fe_groups g
inner join fe_groups_extrainfo x on g.uid = x.usergroup
set
g.description = x.usernames;
Sorry it is not a single SQL Statement as the mariadb-SQL statement but still simpler as programming a custom TYPO3 extension with a complex backend module.
Update 09/2022:
It is essential to update the TYPO3 Reference Index after using this method (direct db-access with SQL-UPDATE statements).
typo3cms referenceindex:update
Otherwise the "Ref" column in the "List" module view would still show a "-" (meaning 0) users belong in this feuser-group. After updating the refindex the "[Ref]" column will then display the approximate count of feusers.

Related

uSync Dropdown DataType Issue

I have 2 sites, dev branch and production. On my dev branch I'm using a couple of archetype DataType which are able to be configured by a simple dropdown with couple color names (like Green, Blue etc). I have like 300 published nodes which uses that datatype (required field). After I've exported "Full Export" in uSync dashboard and then copy/pasted the whole uSync folder to my production branch and clicked "Full Import". After import complete I check my nodes. All fields are there except that dropdown.
There are some old issues on the our.umbraco.com website stating the same issue, but they seem to been fixed.
I've posted there this issue, but has been 6 days, and the topic still is on manual approval.
Any idea what must be causing this issue?
I am using (uSync.BackOffice 4.0.16.0) (uSync.Core 6.0.15.0) [uSync.Content: 4.1.9.1]
Umbraco version 7.15.4
Thank you in advance.
Best regards,
Artur
PS. I am unable to create the USync label. Would appreciate if someone would edit with it!
I'd open up the database and look at the values in the cmsDataTypePreValues table. I suspect that uSync has changed the prevalues out from under you. Prevalues are really tricky and uSync does its best given the circumstances. You'll notice that the uSync .def files in Umbraco 7 don't record any unique ids on those prevalues. They just get inserted into the database and are assigned an id automatically. This means if the prevalues are deleted and recreated, they will have different ids. If those dropdown prevalues are being picked by the id field on the cmsDataTypePreValues record, that is probably what is going wrong.
Use the following query to see your prevalues for the datatype:
DECLARE #dataTypeNodeId AS INT = <dataTypeNodeId, INT, 0>
SELECT *
FROM cmsDataType dt
INNER JOIN cmsDataTypePreValues pv
ON pv.datatypeNodeId = dt.nodeId
WHERE dt.nodeId = #dataTypeNodeId
Compare the values you see here between the dev database and the production database. To help give you a better picture of what the data looks like, you could also run this query to see what the actual picked values look like. The query is so long because it is filtering out results from old versions. This might not work very well for you because your datatype is inside of Archetype. Hopefully it can still give you an idea about what selected dropdown values actually look like in the database.
DECLARE #dataTypeNodeId AS INT = <dataTypeNodeId, INT, 0>
SELECT TOP 1000 n.id
,n.[text]
,n.[path]
,pt.[alias] AS 'property alias'
,dtn.id AS 'Datatype Id'
,dtn.[text] AS 'Datatype Name'
,dtn.uniqueID AS 'Datatype Guid'
,d.templateId
,t.[alias] AS 'template alias'
,pd.dataInt
,pd.dataDate
,pd.DataNvarchar
,pd.dataNtext
,cv.VersionDate
FROM umbracoNode n
INNER JOIN cmsDocument d
ON d.nodeId = n.id
INNER JOIN cmsContentVersion cv
ON cv.VersionId = d.versionId
INNER JOIN cmsPropertyData pd
ON pd.contentNodeId = n.id AND pd.versionId = d.versionId
INNER JOIN cmsPropertyType pt
ON pt.id = pd.propertytypeid
INNER JOIN cmsDataType dt
ON dt.nodeId = pt.dataTypeId
INNER JOIN umbracoNode dtn
ON dtn.id = dt.nodeId
LEFT OUTER JOIN cmsTemplate t
ON t.nodeId = d.templateId
WHERE d.newest = 1
AND dtn.id = #dataTypeNodeId
You can try to manually fix the prevalue entries in the database. I've run into enough prevalue trouble with Umbraco dropdowns that I try to always use something like nuPickers to avoid picking prevalues by id.

Do ampersands work for user input in reports?

I have a working query that goes something like this:
Base table ACCT, link to others (listagg/subqueries) and ensure matching year("rollyear") field. Then the final step is to say which year ACCT table is in.
SELECT
FROM table ACCT
FULL OUTER JOIN table TABLE2 on ACCT.id = TABLE2.id and ACCT.rollyear= TABLE2.rollyear
...
FULL JOIN table TABLE7 on ACCT.id = TABLE7.id and ACCT.rollyear= TABLE7.rollyear
where ACCT.rollyear = extract (year from sysdate) +1
I typically use the calendar year plus one. I've been playing with using ACCT.rollyear = &rollyear to get user input... The limitation/issue I have is getting that running using the "User Defined Reports" feature.
Am I using this feature correctly? Does that only work for SQL Queries and not reports? Ive seen videos/comments about Stored Procedures and using "Accept...." but my attempts to mimic give errors and I'm not sure I'm on the right track. Thanks for any advice.
Change your query to use a bind variable:
where ACCT.rollyear = :rollyear
Then in the 'Binds' section you will see a variable with that name:
When you run your query you'll then be prompted to supply the value:

TYPO3 7.6 Backend module to list values from several tables

I have been struggling for some time now and I can't really find anyone having done the same thing before.
I'm creating a backend module in TYPO3 7.6 which belongs to a shop extension.
The shop extension with the backend module was created with the extension builder. The shop has the following three models:
Product (products which can be ordered through the shop)
Productsorder (link to the customer)
ProductsorderPosition (the ordered product, the ordered amount and size and the link to the Productsorder)
The customers are of a model type from a different extension. These customers are linked to fe_users.
Now what I wanna do in my backend module is getting an overview to all these orders listed with the customer, some information about the fe_user and of course the product. I have created a sql-query, which does exactly that:
SELECT p.productname, p.productpriceperpiece,
pop.amount, pop.size,
h.name, h.address, h.zipcode, h.city, h.email, h.phone,
f.first_name, f.last_name, f.email
FROM `tx_gipdshop_domain_model_productorderposition` AS pop
JOIN `tx_gipdshop_domain_model_product` AS p ON pop.products = p.uid
JOIN `tx_gipdshop_domain_model_productsorder` AS po ON pop.productorder = po.uid
JOIN `tx_gipleasedisturbhotels_domain_model_hotel` AS h ON po.hotel = h.uid
JOIN `fe_users` AS f ON h.feuser = f.uid
If I use this query from the product repository it gives back the right amount of data records but they're of type product and the products are all "empty" (uid = 0 etc).
I've added an additional action for this in the product controller (getOrdersAction) and in the repository containing the query I've added a method findAllOrders.
I'm still rather a beginner in TYPO3 but I can somehow understand why it returns data sets of type Product when the query is called from the ProductRepository. But what I do not know is how I can get all the information from the query above and list it in the backend module.
I've already thought about moving the query to the ProductsorderPositionRepository but I would probably be faced with a similar problem, it would only return the information from the ProductsorderPosition and everything else would be left out.
Can someone point me to the right direction?
Would I need to create another model with separate repository and controller? Isn't there an easier way?
If you need more information, just ask! ;)
First of all, you are doing a joined query with subsets of data mixed from multiple tables. There is nothing against this.
Because of this, there is no "model" which has the mixed datasets.
If you are using the default query thing in a repository, the magic behind the repository assumes that the result of the query statement reflects the defined base model for this repository.
Moving the query function to another repository does not solve the problem.
You have not provided the code snippet you are executing the sql statement, so I assume you have used the query thing in the repository to execute the statement. Something like this:
$result = $query->statement('
SELECT p.productname, p.productpriceperpiece,
pop.amount, pop.size,
h.name, h.address, h.zipcode, h.city, h.email, h.phone,
f.first_name, f.last_name, f.email
FROM `tx_gipdshop_domain_model_productorderposition` AS pop
JOIN `tx_gipdshop_domain_model_product` AS p ON pop.products = p.uid
JOIN `tx_gipdshop_domain_model_productsorder` AS po ON pop.productorder = po.uid
JOIN `tx_gipleasedisturbhotels_domain_model_hotel` AS h ON po.hotel = h.uid
JOIN `fe_users` AS f ON h.feuser = f.uid', NULL);
or have used the query building stuff.
First solution
The first and simpliest solution would be to retrieve the result as plain php array. Before TYPO3 7.0 you could have done this by using this:
$query->getQuerySettings()->setReturnRawQueryResult(TRUE);
With TYPO3 7.0 this deprecated method was removed from the core.
The only way is to define the query and call $query->execute(TRUE); for now.
This should return the data in pure array form.
This is the simpliest one, but as we are in the extbase context this should not be suffering enough.
Second Solution - no, just an idea that I would try next
The second solution means that you have some work to do and is for now only a suggestion, because I have not tried this by myself.
Create a model with the properties and getter/setters for the result columns of your query
Create a corresponding repository
Third solution
Not nice, but if nothing else works, fall back to the old TYPO3 v4 query methods:
$GLOBALS['TYPO3_DB']->exec_SELECTgetRows([...]))
and replace this with the QueryBuilder in/for TYPO3 v8.
This is really not nice.
I hope I could direct you to the right way, even if not giving a full solving solution.

Changing a DB View dynamically according the current user-group

we are currently digging into Amazon Redshift and testing different functionalities.
One of our basic requirements is that we will define different user groups which in turn will be granted access to different views.
One way to go about this would be to implement one view seperately for each user-group. However, since we have a lot of user-groups that share almost the exact same need for information, I'm looking for a way to implement this more dynamically in Redshift.
For instance, let's say I have a user group called users_london and another one called users_berlin. Both will have access to a view called v_employee_master_data which contains the columns employee_name, employee_job_title and employee_city.
Both groups share the same scope of information with one exception - the column employee_city.
In essence, the view should be pre-filtered for a certain value in the column employee_city according to the currently logged-in user-group.
In SQL - something like this:
For the usergroup users_london:
SELECT * FROM v_employee_master_data WHERE employee_city = 'London';
For the usergroup users_berlin:
SELECT * FROM v_employee_master_data WHERE employee_city = 'Berlin';
Now to make the connection back to Amazon Redshift. Does the underlying DB runtime provide an out-of-the-box functionality to somehow catch the currently logged user-group as a form of global variable and alter the SQL-statement according to the value of that variable?
It is possible to do:
get current user
select current_user
find what group it belongs to
select groname from pg_group where current_user_id = any(grolist);
Extract city and capitalize it:
select initcap(substring(groname from 'users_(.*)')) from pg_group where current_user_id = any(grolist);
Now you have your city based on the "user". So just inject it in the view
... WHERE employee_city = initcap(substring(groname from 'users_(.*)') ...

Can't remap fields - map fields window is missing new table

I have a Crystal Report with a database command:
The command has a join clause that can be removed and read from a table in the database, because it represents static data. I add this table (called _System) to the database expert:
Now I edit the command to remove the join and columns that reference this table. Since the report fields that depended on these columns are no longer mapped, this causes the Map Fields window to appear:
...which does not have the new table in it. If I cancel out of this I am back to where I originally was. If I hit OK without mapping, all of the unmapped fields on the report are deleted (suffice it to say... I was not expecting this >:( )
I have tried adding links between the command and the new table, and refreshing report parameters, but these have had no effect.
One workaround is to manually replace every field in the report, but this is very labour intensive.
Here is the outline of the command before:
SELECT ACT.Account_Code, ACT.Company, ACT.FName, --etc
STM.CompanyName AS 'DLRName', STM.Address_1 AS 'DLRAddress', STM.City AS 'DlrCity' --etc
FROM Accounts AS ACT
JOIN _System AS STM ON 1 = 1
GROUP BY ACT.Account_Code, ACT.Company, ACT.FName, --etc
STM.CompanyName, STM.Address_1, STM.City --etc
And after:
SELECT ACT.Account_Code, ACT.Company, ACT.FName, --etc
FROM Accounts AS ACT
GROUP BY ACT.Account_Code, ACT.Company, ACT.FName --etc
I have removed the JOIN on the _System table, and all referenced columns.
It appears to not be recognizing your _system table as a new source.
I would :
1) leave your command object SQL unchanged & get the issue worked out with the _System table, then
2) ensure that you are able to establish a join between the command object fields and the _System table fields, and lastly
3) then remap the fields.
Step two I suspect is the source of the problem, as your join condition is "ON 1 = 1" which I assume to mean that you may not have a common key field in both tables.
Note that your original command SQL selects STM.Companyname AS 'DLRName'.
Hence, crystal now know of a field called DLRName, but does not know of a field called CompanyName, hence it cannot make the association between DLRName in the old source, and CompanyName in the new source...
Likewise with the rest of the fields that are being moved from the command object to an attached table. if no name match exists...Crystal cant make the connection. However...it would list all unmatched fields that are on the report, and all unused fields in the recognized data sources, and allow you to specify the matches yourself.
But it does not...which tells me that something has gone wrong with the attempt to attach/open the _System table. Hence..you need to get that worked out first, then make the field adjustments.
If this doesnt get you thru...then show some sample data so I can see how the two tables are relating ( ensure some examples exists where there is a row match from both tables ).
I had the same problem a while ago.
Unfortunately I can't find anything online that helps, or maybe wasn't looking hard enough. I just noticed that in my case, that particular field that isn't showing in the map field dialogue box has nvarchar(max) as its datatype (in view).
I tried to force the datatype with CAST(missingfieldname as nvarchar(20)) as missingfieldname (I did this in the view), and voila, it magically appears in the map field dialogue box.
It seems that field mapping dialogue box aren't showing fields with blob texts.
I know this question was asked 4 years ago. But hopefully, this comment could help future solution seekers regarding this absurd and weird problem. I just got lucky seeing what's unique about that particular missing field.