Your example appears to be for a later version of asp.net zero angular/core than I have (6.9.0), but it got me pointed in the right direction.
Turns out I just needed to modify app-ui-customization-service.ts to auto expand the item I wanted (the "Process" menu):
getSideBarMenuItemClass(item, isMenuActive) {
let menuCssClass = 'm-menu__item';
if (item.items.length) {
menuCssClass += ' m-menu__item--submenu';
//expand process menu by default
if (item.name == 'Process') {
//set expanded, but not active
menuCssClass += ' m-menu__item--open m-menu__item--expanded';
}
}
if (isMenuActive) {
menuCssClass += ' m-menu__item--open m-menu__item--expanded m-menu__item--active';
}
return menuCssClass;
}
Referenced by side-bar-menu-component.html:
<ng-template #mMenuItem let-item="item" let-parentItem="parentItem">
<li *ngIf="showMenuItem(item)"
class="{{ui.getSideBarMenuItemClass(item, isMenuItemIsActive(item))}}"
aria-haspopup="true"
[attr.m-menu-submenu-toggle]="ui.getItemAttrSubmenuToggle(item, parentItem)"
>
Thanks!
Hi - thanks - do you have an example you can provide?
Thanks @ismcagdas. I read through the GH issue and am wondering about role mapping. I have several roles defined in the system with varied permissions and cannot have a generic default role that all O365 AD authenticated users map to. i.e. I need to be able to create the user in the system with classic authentication, assign classic roles to that user, then at auth time using O365 AD map the user back to that classic user and the assigned roles. How can we make this happen?
HTML:
<button (click)="exportToExcelTransactions()" class="btn btn-outline-success"> <i class="fa fa-file-excel"></i> {{l("ExportToExcel")}} </button>
Here is the API-side method:
public async Task<FileDto> GetJournalVoucherTransactionsToExcel(GetAllJournalVoucherTransactionsForExcelInput input)
{
var filteredJournalVoucherTransactions = _journalVoucherTransactionRepository.GetAll()
.WhereIf(!string.IsNullOrWhiteSpace(input.Filter), e => false || e.CostpointProjectCode.Contains(input.Filter) || e.CostpointAccountNumber.Contains(input.Filter) || e.AccountAbbreviation.Contains(input.Filter) || e.CostpointOrganizationCode.Contains(input.Filter) || e.TransactionDescription.Contains(input.Filter) || e.TransactionNotes.Contains(input.Filter) || e.CostpointEmployeeNumber.Contains(input.Filter) || e.ProblemCodes.Contains(input.Filter) || e.TransactionState.Contains(input.Filter))
.WhereIf(input.MinLineNumberFilter != null, e => e.LineNumber >= input.MinLineNumberFilter)
.WhereIf(input.MaxLineNumberFilter != null, e => e.LineNumber <= input.MaxLineNumberFilter)
.WhereIf(!string.IsNullOrWhiteSpace(input.CostpointProjectCodeFilter), e => e.CostpointProjectCode.ToLower() == input.CostpointProjectCodeFilter.ToLower().Trim())
.WhereIf(!string.IsNullOrWhiteSpace(input.CostpointAccountNumberFilter), e => e.CostpointAccountNumber.ToLower() == input.CostpointAccountNumberFilter.ToLower().Trim())
.WhereIf(!string.IsNullOrWhiteSpace(input.AccountAbbreviationFilter), e => e.AccountAbbreviation.ToLower() == input.AccountAbbreviationFilter.ToLower().Trim())
.WhereIf(!string.IsNullOrWhiteSpace(input.CostpointOrganizationCodeFilter), e => e.CostpointOrganizationCode.ToLower() == input.CostpointOrganizationCodeFilter.ToLower().Trim())
.WhereIf(input.MinTransactionAmountUSDFilter != null, e => e.TransactionAmountUSD >= input.MinTransactionAmountUSDFilter)
.WhereIf(input.MaxTransactionAmountUSDFilter != null, e => e.TransactionAmountUSD <= input.MaxTransactionAmountUSDFilter)
.WhereIf(!string.IsNullOrWhiteSpace(input.TransactionDescriptionFilter), e => e.TransactionDescription.ToLower() == input.TransactionDescriptionFilter.ToLower().Trim())
.WhereIf(!string.IsNullOrWhiteSpace(input.TransactionNotesFilter), e => e.TransactionNotes.ToLower() == input.TransactionNotesFilter.ToLower().Trim())
.WhereIf(!string.IsNullOrWhiteSpace(input.CostpointEmployeeNumberFilter), e => e.CostpointEmployeeNumber.ToLower() == input.CostpointEmployeeNumberFilter.ToLower().Trim())
.WhereIf(input.MinHoursFilter != null, e => e.Hours >= input.MinHoursFilter)
.WhereIf(input.MaxHoursFilter != null, e => e.Hours <= input.MaxHoursFilter)
.WhereIf(!string.IsNullOrWhiteSpace(input.ProblemCodesFilter), e => e.ProblemCodes.ToLower() == input.ProblemCodesFilter.ToLower().Trim())
.WhereIf(input.MinJournalVoucherIDFilter != null, e => e.JournalVoucherID >= input.MinJournalVoucherIDFilter)
.WhereIf(input.MaxJournalVoucherIDFilter != null, e => e.JournalVoucherID <= input.MaxJournalVoucherIDFilter)
.WhereIf(!string.IsNullOrWhiteSpace(input.TransactionStateFilter), e => e.TransactionState.ToLower() == input.TransactionStateFilter.ToLower().Trim());
var query = (from o in filteredJournalVoucherTransactions
select new GetJournalVoucherTransactionForViewDto() {
JournalVoucherTransaction = new JournalVoucherTransactionDto
{
LineNumber = o.LineNumber,
CostpointProjectCode = o.CostpointProjectCode,
CostpointAccountNumber = o.CostpointAccountNumber,
AccountAbbreviation = o.AccountAbbreviation,
CostpointOrganizationCode = o.CostpointOrganizationCode,
TransactionAmountUSD = o.TransactionAmountUSD,
TransactionDescription = o.TransactionDescription,
TransactionNotes = o.TransactionNotes,
CostpointEmployeeNumber = o.CostpointEmployeeNumber,
Hours = o.Hours,
ProblemCodes = o.ProblemCodes,
JournalVoucherID = o.JournalVoucherID,
TransactionState = o.TransactionState,
Id = o.Id
}
});
var journalVoucherTransactionListDtos = await query.ToListAsync();
return _journalVoucherTransactionsExcelExporter.ExportToFile(journalVoucherTransactionListDtos);
}
Here is the angular call:
async exportToExcelTransactions() {
//inform user
this.notify.info(this.l('Excel file generation initiated...'));
//changed this to wait for result instead of using subscribe -
//will hopefully solve problem of downloaded files sometimes being empty.
var resultFile = await this._journalVoucherTransactionsServiceProxy.getJournalVoucherTransactionsToExcel(
this.filterText,
this.maxLineNumberFilter == null ? this.maxLineNumberFilterEmpty: this.maxLineNumberFilter,
this.minLineNumberFilter == null ? this.minLineNumberFilterEmpty: this.minLineNumberFilter,
this.costpointProjectCodeFilter,
this.costpointAccountNumberFilter,
this.accountAbbreviationFilter,
this.costpointOrganizationCodeFilter,
this.maxTransactionAmountUSDFilter == null ? this.maxTransactionAmountUSDFilterEmpty: this.maxTransactionAmountUSDFilter,
this.minTransactionAmountUSDFilter == null ? this.minTransactionAmountUSDFilterEmpty: this.minTransactionAmountUSDFilter,
this.transactionDescriptionFilter,
this.transactionNotesFilter,
this.costpointEmployeeNumberFilter,
this.maxHoursFilter == null ? this.maxHoursFilterEmpty: this.maxHoursFilter,
this.minHoursFilter == null ? this.minHoursFilterEmpty: this.minHoursFilter,
this.problemCodesFilter,
this.journalVoucherIdFilter == null ? this.maxJournalVoucherIDFilterEmpty: this.journalVoucherIdFilter,
this.journalVoucherIdFilter == null ? this.minJournalVoucherIDFilterEmpty: this.journalVoucherIdFilter,
this.transactionStateFilter
).toPromise();
//wait a couple secs before downloading
await this.delay(4000); //4 seconds
//inform user
this.notify.success(this.l('Excel file download starting...'));
//download Excel file
this._fileDownloadService.downloadTempFile(resultFile);
//return promise to notify caller
return new Promise(resolve => {
resolve(resultFile);
});
}
And this is the HTML:
<button
(click)="exportToExcelTransactions()"
class="btn btn-outline-success">
<i class="fa fa-file-excel"></i> {{l("ExportToExcel")}}
</button>
If the user requests hard refresh of page in Chrome (CTRL + F5), the file downloads completely, otherwise in normal usage, many users are consistently only receiving the header row in the downloaded spreadsheet.
Thoughts?
That seemed to do the trick - thanks!
Hi,
The addition of AbpHttpInterceptor references as suggested worked for passing authentication to the upload httppost method. The method can be adorned with [AbpAuthorize] successfullly and once inside the method, I can see the user object is populated. Thank you.
[HttpPost]
[AbpMvcAuthorize]
//[AbpAuthorize,
// AbpMvcAuthorize,
// AbpMvcAuthorize(AppPermissions.Pages_ProcessCashSheets),
// AbpMvcAuthorize(AppPermissions.Pages_ProcessCashSheets_CashSheetBatches_Create),
// AbpMvcAuthorize(AppPermissions.Pages_ProcessCashSheets_CashSheetBatches_Edit)]
public async Task<JsonResult> ImportFromExcel()
{
try
{
var file = Request.Form.Files.First();
//TODO: parse file name for batch number and org, etc.
if (file == null)
{
...
User obj is populated:
?AbpSession.ToUserIdentifier()
{3@1} TenantId: 1 UserId: 3
I just have one follow-up question. Once further along inside the method, when I make a call to an app object to interact with (PowerTools generated) entity objects, if the method is adorned with any [AbpAuthorize] tag, an error "Current user did not login to the application!" is thrown.
CashSheetTransactionAppService.cs:
namespace SchlarmanConsulting.OneTAFUnify.CashSheets { [AbpAuthorize] //if I remove this everything works public class CashSheetTransactionsAppService : OneTAFUnifyAppServiceBase, ICashSheetTransactionsAppService { private readonly IRepository<CashSheetTransaction> _cashSheetTransactionRepository; private readonly ICashSheetTransactionsExcelExporter _cashSheetTransactionsExcelExporter;
public CashSheetTransactionsAppService(IRepository<CashSheetTransaction> cashSheetTransactionRepository, ICashSheetTransactionsExcelExporter cashSheetTransactionsExcelExporter )
{
_cashSheetTransactionRepository = cashSheetTransactionRepository;
_cashSheetTransactionsExcelExporter = cashSheetTransactionsExcelExporter;
}
...
[AbpAuthorize] private async Task Create(CreateOrEditCashSheetTransactionDto input) { var cashSheetTransaction = ObjectMapper.Map<CashSheetTransaction>(input);
await _cashSheetTransactionRepository.InsertAsync(cashSheetTransaction);
}
...
When I attempt to call this further along after the httppost method entry,
//Create insertable object
var cashSheetTransaction = new CreateOrEditCashSheetTransactionDto
{
CashSheetBatchID = input.CashSheetBatchID,
CashSheetBatchAccountSummaryID = input.CashSheetBatchAccountSummaryID,
CostpointProjectCode = input.CostpointProjectCode,
CostpointAccountNumber = input.CostpointAccountNumber,
AccountAbbreviation = input.AccountAbbreviation,
CostpointOrganizationCode = input.CostpointOrganizationCode,
TransactionDescription = input.TransactionDescription,
TransactionAmountUSD = input.TransactionAmountUSD,
QBAccountNumber = input.QBAccountNumber,
QBAmount = input.QBAmount,
QBDescription = input.QBDescription,
QBPayee = input.QBPayee,
QBTransactionDate = input.QBTransactionDate,
QBTransactionNumber = input.QBTransactionNumber,
TransactionState = input.TransactionState,
ProblemCodes = input.ProblemCodes,
BankAccountID = input.BankAccountID,
CashSheetBankAccountDescription = input.CashSheetBankAccountDescription
//Id = 0
};
//Create new transaction
//await _cashSheetTransactionRepository.InsertAsync(cashSheetTransaction);
await _cashSheetTransactionsAppService.CreateOrEdit(cashSheetTransaction);
I receive the error:
?exception {"Current user did not login to the application!"} Data: {System.Collections.ListDictionaryInternal} HResult: -2146233088 HelpLink: null InnerException: null Message: "Current user did not login to the application!"
I don't understand how the credentials could be lost along the way once inside the API method. I also started from scratch and made sure I logged on fresh to eliminate that possibility.
Thoughts?
Hi @ismcagdas - no, still have not solved this.
Hi again - could you tell me how the abp auth works User method "ImportFromExcel" (of UsersControllerBase.cs) and not my clone of that class/method (CashSheetsControllerBase.cs)? Seems I'm missing some config or decorator somewhere, but I've tried everything I can think of. As you can see, I've also tried a straight [AbpMvcAuthorize] (which just requires a user logon, correct?) which doesn't work either.
Any help is much appreciated.
Cheers
Hi,
Yes, I can import users (if the input file contains certain data in the exact right format) and also the httppost method/file upload works without permission error. I think there are some other bugs in the user import (it doesn’t return erroneous records correctly, etc.), but the main thing is I need to get past this permission error. Other thoughts on what to try?
Lastly (but secondary importance), is there a fix for known users import bugs that I can implement without upgrading the template?