내부 제품 관련 업무라 작성을 하지 못하다가

오후 3시에 발표를 한 뒤 다음 업무 할당을 받지 않은 상태라

다시 개인적인 학습 시간을 자체적으로 가지기로 했다.

 

이전부터 쌓인 것 같은 기술부채 느낌으로 보안규칙 정독, 플러그인 설치 및 확인 등 여러가지가 있지만

다음달까지 따야 하는 PD1 자격증 학습이 더 우선일 것 같았고

PD1에 관련된 Trailhead 내용 또한 온보딩 필수 학습 목록에 들어가 있기 때문에

(또한 오후에 시험치면 반차를 쓴 것처럼 시험치고 퇴근이 가능)

업무와 제일 관련있는 PD1 학습을 진행하기로 했다.

 

문제 자체가 영어로 되어 있는데 

사실 한국말로도 조금 횡설수설하는 느낌이 있는 문제도 있는데

이걸 영어로 풀려고 하니 상당히 어려웠다.

 

예전에 학습했지만 시간이 지나 잊은 것들도 있는데

__r을 사용해야 하는지 아닌지 확신이 없었고(__c와 __r 그리고 __미사용)

----잘못된 내용----

상위 필드, 하위 필드 구분도 모호해 보였는데

언급이 없는 것은 당연히 더 많은 것을 포함하는 것이 상위 필드고

하나의 단위인 사람 같은 경우가 하위 룩업 필드로 들어가는 것 같았다.

 

결국 하위 쿼리를 조회하려면 아래와 같이 들어가거나

Select Id, (Select Id From B__r) From A__c where class = 'aa'

상위 쿼리를 포함할 경우 아래와 같이 직접 접근하는 것 같다.

Select Id From B__c where class = A__c.Class

---- 종료 ----

작성 도중에 눈치챘는데 lookup 관계는 상위, 하위 필드가 존재하지 않고

관계만 있는 존재인 것 같다.

 

헷갈려서 작성해본 결과 서로 소통이 되지 않고

생성한 부분의 필드만 들어가기 때문에 상위 하위라는 말은 이상하지만

생성된 부분의 필드만 있는게 맞아서 하위라는 느낌으로 봐도 될 것 같고

직접 TestA, TestB를 만들고 B에 A를 lookup으로 넣어보니 아래의 쿼리는 동작하는 것을 볼 수 있었다.

"select Id, TestA__r.Id from TestB__c"

일단 퇴근 시간 근처기 때문에 여기서 마무리하고 이 부분은 내일 확인해야겠다.

 

 

도중에 등록되지 않은 유저라도 메서드나 트리거를 작동시킬 수 있는데(페이지 접속 등의 행동을 통해)

어떻게 Debug를 할 수 있을지 질문이 들어와서 생각해보다가

New Trace Flag를 확인해보니 해당 부분 내부에서 User만 추적할 수 있는 것이 아니고

Process, Class, Trigger 또한 추적이 가능한걸 알 수 있었다.

User만 되는줄 알았는데!!

어쨌건 특정 부분만 Debug 추적이 가능하다는 것을 알게 되었다.

 

 

 

 

 

(1).백준 5612번 터널의 입구와 출구는 각각 터널로 들어온 차의 수량과

터널에서 나간 차량의 수량을 제공하며

2번째 줄에는 초기 터널 내부 차량의 숫자를 제공할 때

제일 차가 많았던 시점의 차 대수를 구하는 문제였고

예외로 차 보유량이 한번이라도 음수가 될 경우

해당 테스트케이스는 0으로 출력해야 하는 조건이 걸려있었다.

 

각각 덧셈, 뺄셈을 진행해 현재 터널의 차량 숫자를 구해준 다음

터널 내부의 차량 숫자를 max와 비교해 max를 계속 갱신한 다음

예외 조건이 발생하지 않은 경우 max를 출력했고

예외 조건이 발생한 경우 진행을 중단하고 max를 0으로 초기화한 다음 출력했다.

const input = `3
2
2 3
2 3
1 0`.split('\n').map(el => el.split(' ').map(Number))


let max = input[1][0]
let now = input[1][0]

for(let i = 2 ; i < input.length ; i++){
    const [add, minus] = input[i]
    now += add - minus
    if(now < 0){
        max = 0
        break
    }
    max = Math.max(max, now)
}

console.log(max)

'회고' 카테고리의 다른 글

[수습일지] - 81  (0) 2023.06.15
[수습일지] - 80  (0) 2023.06.14
[수습일지] - 78  (0) 2023.06.12
[수습일지] - 77(주말)  (0) 2023.06.11
[수습일지] - 76(주말)  (0) 2023.06.10

오늘도 무난하게 과제를 진행했다.

 

내일부터 발표일까지는 바쁘게 돌아갈 확률이 상당히 높기 때문에

컨디션 관리를 위해 탄산음료나 인스턴트 식품을 먹지 않고

과자도 먹지 않았다..

하루종일 찍은 사진은 오렌지 한장

 

일기를 쓸 때만 생각나지만

매일 자는 시간이 늦어지면 안되기 때문에 계속 미루고 있는

동원훈련 후 집으로 복귀하는 표 예매는 목요일 저녁에나 할 수 있을 것 같다.

 

오늘 드디어 페이지를 만들거라고 기대하고 작업을 시작했지만

apex를 연동하는 부분에서 엄청 에러가 발생해서 진행이 되지 않았다.

 

분명 admin으로는 잘 됐지만 partner 계정으로는 진행이 되지 않았는데

이 상태에서 제일 많이 의심했던 부분은 파트너 커뮤니티의 DML 요청은 sharing rull 적용이 되지 않는 것이었다.

 

하지만 해당 내용으로 검색해보고 sharing 부분 수정과 프로필 내부 옵션 확인 등과

파트너 커뮤니티 생성 페이지의 옵션, builder 내부 setting 등 여러가지 시도를 했지만 해결이 되지 않았고

6시간 이상 시간을 허비한 끝에 포기하고 자기로 했다.

 

최후의 보루로 질문 찬스를 사용하기 위해 세일즈포스 단톡방과 디스코드 세일즈포스 개발자방에 질문을 남기고 자려고 했는데

(접속 시간대가 다르기 때문에 질문 답변이 늦는 경우도 많아서 일어나서 처리 후 결과에 대해 알려주는 방식으로 진행했다)

디스코드 질문을 작성하고 일기를 쓰려고 하는 시점에서 카톡에 이미 답변이 달려있었다.

 

문제와 직접적인 연관은 없지만 최대한 정보를 주기 위해 했던 말 중에 하나인 "로그가 찍히지 않는다" 부분에 대한 조언인데

해당 계정을 디버그에 연동시켰는지를 묻는 이야기였고 

생각해보면 당연히 타 계정의 작동에 대한 디버그가 관리자라고 하더라도 설정 없이 찍힐리가 없었다.

 

컨디션 조절을 위해 마무리를 해야 하는 시점이었지만

해당 조언에 대한 피드백 처리를 알려주지 않고 그냥 자버리기는 찜찜하기도 하고

파면 팔수록 연관된 에러가 나오며 하나씩 문제가 해결되고 있어서 잘 수가 없었다.

 

회고에도 이미 다 적은 내용이라 요약하자면

메서드 연동을 성공적으로 진행해서 파트너도 권한에 맞는 정보를 잘 볼 수 있게 되었다.

 

이제 할만한 페이지 구성 및 테스트코드 작성과

조금 어려울 것 같은 파일 업로드 및 확인, 페이지 추가, 삭제, 생성기능

마지막으로 ppt 처리가 남았는데

페이지 구성 3~4시간, 테스트코드 1시간, 파일 업로드 3~4시간

페이지 추가, 삭제, 생성기능 및 해당 페이지 5~6시간, ppt 6~8시간이 남았다.

대략 23시간이 남은 것 같은데 화, 수 2일간 거의 끝낼 수 있으면 좋겠지만

회사에서 출시중인 제품 테스트 참여도 해야 하기 때문에 화,수는 8~9시까지 회사에 있을 것 같다.

(재미 있어서 계속 지원했다)

 

어쨌건 수면시간이 1시간 이상 줄어들었지만 

오늘 꿈에서도 네다섯번 깨면서 꿈속에서 문제 해결을 하려고 했었는데

하루 종일 막혀있던 문제를 해결하고 잘 수 있기 때문에 편안한 마음으로 잘 수 있을 것 같다.

 

 

오늘도 10분 이상 운동했다.

'일기' 카테고리의 다른 글

야근 성공..  (0) 2023.05.31
야근 실패  (0) 2023.05.30
과제 진행  (0) 2023.05.28
대청소  (2) 2023.05.27
벌써 주말  (1) 2023.05.26

1.Apex jobs에서는 모든 비동기 Apex 작업이 표시되며

jobId를 사용해 아래와 같이 쿼리로 조회할 수도 있다.

AsyncApexJob jobInfo = [SELECT Status, NumberOfErrors
    FROM AsyncApexJob WHERE Id = :jobID];

 

 

2.(Quick Start: Lightning Web Components)

Trailhead Playground 사용자 이름 및 비밀번호 받기는 playground에서 아래와 같은 절차로 진행된다.

  1. Login Credentials을 playground에서 받아둔다.
  2. 탭을 클릭 하고 사용자 이름을 기록
  3. 내 비밀번호 재설정을 클릭 
  4. 이메일에 전송된 링크를 클릭
  5. 비밀번호 변경을 클릭 후 새 비밀번호를 입력

또한 sfdx update를 CLI 부분에 입력해 최신 버전인지를 확인해야 한다.

 

 

3.Quick Start: Lightning Web Components 부분 선행 요청으로 트레일을 수행하던 중

SFDX: Authorize an Org를 선택할 수 없는 문제가 발생했다.

 

예전에도 비슷한 경험이 있었던 것 같은데 검색을 해보니

생성을 한 직후에 이렇게 잡히지 않는 경우가 있는데

open→folder로 folder를 인식시켜주면 다시 SFDX: Authorize an Org를 선택할 수 있다.

 

 

4.Lightning web component에는 폴더 이름과 네임스페이스가 존재하는데

폴더 이름의 공백은 IDE 내부에서는 허용하지 않기 때문에 카멜케이스(’aaBb’)로 작성하고

태그에서 참조하려면 공백은 하이폰(’-’)으로 치환되기 때문에 <aa-bb>로 사용하게 된다.

 

 

5.Lightning Web Components Basics과정을 따라가다 보면 자전거 띄우기가 나오는데

실제 lightning app builder에 들어가면 나오지 않는 것을 볼 수 있다.

 

이건 기본 생성에는 target이 잡혀있지 않기 때문인데

아래와 같은 target 추가를 통해 app builder에서도 작성한 페이지를 사용할 수 있다.

 

또한 isExposed가 false로 default 잡혀있는데

이런 경우 Lightning 앱 빌더 또는 익스피리언스 빌더에 노출되지 않기 떄문에

true 및 target 설정을 해야 한다.

(true를 하고 target 설정을 하는 과정인 것 같다)

//html
<template>
    <div>
        <div>Name: {name}</div>
        <div>Description: {description}</div>
        <div>Category: {category}</div>
        <div>Material: {material}</div>
        <div>Price: {price}</div>
        <div><img src={pictureUrl}/></div>
    </div>
</template>

//js
import { LightningElement } from 'lwc';
export default class App extends LightningElement {
   name = 'Electra X4';
   description = 'A sweet bike built for comfort.';
   category = 'Mountain';
   material = 'Steel';
   price = '$2,700';
   pictureUrl = 'https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/electrax4.jpg';
}

//meta
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>56.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
      <target>lightning__AppPage</target>
      <target>lightning__RecordPage</target>
      <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>

정확히는 isExposed를 true로 할 경우 구성 요소를 다른 네임스페이스에서 사용할 수 있도록 하며

true 또는 false의 값을 필수적으로 기입해야 한다.

 

하지만 targets 부분은 선택적 요소로 앱 빌더에서 구성 요소를 추가할 수 있는 유형을 지정한다.

 

 

6.아래와 같은 data, detail, list, selector, tile 코드를 작성해

페이지를 구성할 수 있다.

//selector html
<template>
    <div class="wrapper">
    <header class="header">Available Bikes for {name}</header>
    <section class="content">
        <div class="columns">
        <main class="main" >
            <c-list onproductselected={handleProductSelected}></c-list>
        </main>
        <aside class="sidebar-second">
            <c-detail product-id={selectedProductId}></c-detail>
        </aside>
        </div>
    </section>
    </div>
</template>

//selector js
import { LightningElement, wire } from 'lwc';
import { getRecord, getFieldValue } from 'lightning/uiRecordApi';
import Id from '@salesforce/user/Id';
import NAME_FIELD from '@salesforce/schema/User.Name';
const fields = [NAME_FIELD];
export default class Selector extends LightningElement {
    selectedProductId;
    handleProductSelected(evt) {
        this.selectedProductId = evt.detail;
    }
    userId = Id;
    @wire(getRecord, { recordId: '$userId', fields })
    user;
    get name() {
        return getFieldValue(this.user.data, NAME_FIELD);
    }
}

//selector css
body {
  margin: 0;
} 
.wrapper{
  min-height: 100vh;
  background: #ccc;
  display: flex;
  flex-direction: column;
}
.header, .footer{
  height: 50px;
  background: rgb(255, 255, 255);
  color: rgb(46, 46, 46);
  font-size: x-large;
  padding: 10px;
}
.content {
  display: flex;
  flex: 1;
  background: #999;
  color: #000; 
}
.columns{
  display: flex;
  flex:1;
}
.main{
  flex: 1;
  order: 2;
  background: #eee;
}
.sidebar-first{
  width: 20%;
  background: #ccc;
  order: 1;
}
.sidebar-second{ 
  width: 30%;
  order: 3;
  background: #ddd;
}

//selector meta
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>48.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>

//------------------------------------------------------------------

//data.js
export const bikes = [
    {"apiName":"Product__c","childRelationships":{},"fields":{"Category__c":{"displayValue":"Mountain","value":"Mountain"},"CreatedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Description__c":{"displayValue":null,"value":"A durable e-bike with great looks."},"Id":{"displayValue":null,"value":"a0256000001F1arAAC"},"LastModifiedDate":{"displayValue":null,"value":"2018-10-12T02:57:48.000Z"},"Level__c":{"displayValue":"Racer","value":"Racer"},"MSRP__c":{"displayValue":"$7,800","value":7800},"Material__c":{"displayValue":"Carbon","value":"Carbon"},"Name":{"displayValue":null,"value":"DYNAMO X1"},"Picture_URL__c":{"displayValue":null,"value":"https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/dynamox1.jpg"},"SystemModstamp":{"displayValue":null,"value":"2018-10-12T02:57:48.000Z"}},"id":"a0256000001F1arAAC","lastModifiedById":null,"lastModifiedDate":"2018-10-12T02:57:48.000Z","recordTypeInfo":null,"systemModstamp":"2018-10-12T02:57:48.000Z"},
    {"apiName":"Product__c","childRelationships":{},"fields":{"Category__c":{"displayValue":"Mountain","value":"Mountain"},"CreatedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Description__c":{"displayValue":null,"value":"A durable e-bike with great looks."},"Id":{"displayValue":null,"value":"a0256000001F1atAAC"},"LastModifiedDate":{"displayValue":null,"value":"2018-10-10T17:26:47.000Z"},"Level__c":{"displayValue":"Racer","value":"Racer"},"MSRP__c":{"displayValue":"$6,802","value":6802},"Material__c":{"displayValue":"Aluminum","value":"Aluminum"},"Name":{"displayValue":null,"value":"DYNAMO X2"},"Picture_URL__c":{"displayValue":null,"value":"https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/dynamox2.jpg"},"SystemModstamp":{"displayValue":null,"value":"2018-10-10T17:26:47.000Z"}},"id":"a0256000001F1atAAC","lastModifiedById":null,"lastModifiedDate":"2018-10-10T17:26:47.000Z","recordTypeInfo":null,"systemModstamp":"2018-10-10T17:26:47.000Z"},
    {"apiName":"Product__c","childRelationships":{},"fields":{"Category__c":{"displayValue":"Mountain","value":"Mountain"},"CreatedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Description__c":{"displayValue":null,"value":"A durable e-bike with great looks."},"Id":{"displayValue":null,"value":"a0256000001F1auAAC"},"LastModifiedDate":{"displayValue":null,"value":"2018-10-09T04:37:56.000Z"},"Level__c":{"displayValue":"Enthusiast","value":"Enthusiast"},"MSRP__c":{"displayValue":"$5,601","value":5601},"Material__c":{"displayValue":"Aluminum","value":"Aluminum"},"Name":{"displayValue":null,"value":"DYNAMO X3"},"Picture_URL__c":{"displayValue":null,"value":"https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/dynamox3.jpg"},"SystemModstamp":{"displayValue":null,"value":"2018-10-09T04:37:56.000Z"}},"id":"a0256000001F1auAAC","lastModifiedById":null,"lastModifiedDate":"2018-10-09T04:37:56.000Z","recordTypeInfo":null,"systemModstamp":"2018-10-09T04:37:56.000Z"},
    {"apiName":"Product__c","childRelationships":{},"fields":{"Category__c":{"displayValue":"Mountain","value":"Mountain"},"CreatedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Description__c":{"displayValue":null,"value":"A durable e-bike with great looks."},"Id":{"displayValue":null,"value":"a0256000001F1avAAC"},"LastModifiedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Level__c":{"displayValue":"Enthusiast","value":"Enthusiast"},"MSRP__c":{"displayValue":"$5,500","value":5500},"Material__c":{"displayValue":"Aluminum","value":"Aluminum"},"Name":{"displayValue":null,"value":"DYNAMO X4"},"Picture_URL__c":{"displayValue":null,"value":"https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/dynamox4.jpg"},"SystemModstamp":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"}},"id":"a0256000001F1avAAC","lastModifiedById":null,"lastModifiedDate":"2018-10-09T03:29:52.000Z","recordTypeInfo":null,"systemModstamp":"2018-10-09T03:29:52.000Z"},
    {"apiName":"Product__c","childRelationships":{},"fields":{"Category__c":{"displayValue":"Mountain","value":"Mountain"},"CreatedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Description__c":{"displayValue":null,"value":"A durable e-bike with great looks."},"Id":{"displayValue":null,"value":"a0256000001F1azAAC"},"LastModifiedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Level__c":{"displayValue":"Enthusiast","value":"Enthusiast"},"MSRP__c":{"displayValue":"$4,600","value":4600},"Material__c":{"displayValue":"Aluminum","value":"Aluminum"},"Name":{"displayValue":null,"value":"FUSE X1"},"Picture_URL__c":{"displayValue":null,"value":"https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/fusex1.jpg"},"SystemModstamp":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"}},"id":"a0256000001F1azAAC","lastModifiedById":null,"lastModifiedDate":"2018-10-09T03:29:52.000Z","recordTypeInfo":null,"systemModstamp":"2018-10-09T03:29:52.000Z"},
    {"apiName":"Product__c","childRelationships":{},"fields":{"Category__c":{"displayValue":"Commuter","value":"Commuter"},"CreatedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Description__c":{"displayValue":null,"value":"A durable e-bike with great looks."},"Id":{"displayValue":null,"value":"a0256000001F1b2AAC"},"LastModifiedDate":{"displayValue":null,"value":"2018-10-09T04:41:56.000Z"},"Level__c":{"displayValue":"Beginner","value":"Beginner"},"MSRP__c":{"displayValue":"$3,200","value":3200},"Material__c":{"displayValue":"Aluminum","value":"Aluminum"},"Name":{"displayValue":null,"value":"ELECTRA X1"},"Picture_URL__c":{"displayValue":null,"value":"https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/electrax1.jpg"},"SystemModstamp":{"displayValue":null,"value":"2018-10-09T04:41:56.000Z"}},"id":"a0256000001F1b2AAC","lastModifiedById":null,"lastModifiedDate":"2018-10-09T04:41:56.000Z","recordTypeInfo":null,"systemModstamp":"2018-10-09T04:41:56.000Z"},
    {"apiName":"Product__c","childRelationships":{},"fields":{"Category__c":{"displayValue":"Commuter","value":"Commuter"},"CreatedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Description__c":{"displayValue":null,"value":"A durable e-bike with great looks."},"Id":{"displayValue":null,"value":"a0256000001F1b3AAC"},"LastModifiedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Level__c":{"displayValue":"Beginner","value":"Beginner"},"MSRP__c":{"displayValue":"$3,200","value":3200},"Material__c":{"displayValue":"Aluminum","value":"Aluminum"},"Name":{"displayValue":null,"value":"ELECTRA X2"},"Picture_URL__c":{"displayValue":null,"value":"https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/electrax2.jpg"},"SystemModstamp":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"}},"id":"a0256000001F1b3AAC","lastModifiedById":null,"lastModifiedDate":"2018-10-09T03:29:52.000Z","recordTypeInfo":null,"systemModstamp":"2018-10-09T03:29:52.000Z"},
    {"apiName":"Product__c","childRelationships":{},"fields":{"Category__c":{"displayValue":"Commuter","value":"Commuter"},"CreatedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Description__c":{"displayValue":null,"value":"A durable e-bike with great looks."},"Id":{"displayValue":null,"value":"a0256000001F1b6AAC"},"LastModifiedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Level__c":{"displayValue":"Beginner","value":"Beginner"},"MSRP__c":{"displayValue":"$2,700","value":2700},"Material__c":{"displayValue":"Aluminum","value":"Aluminum"},"Name":{"displayValue":null,"value":"ELECTRA X3"},"Picture_URL__c":{"displayValue":null,"value":"https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/electrax3.jpg"},"SystemModstamp":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"}},"id":"a0256000001F1b6AAC","lastModifiedById":null,"lastModifiedDate":"2018-10-09T03:29:52.000Z","recordTypeInfo":null,"systemModstamp":"2018-10-09T03:29:52.000Z"},
    {"apiName":"Product__c","childRelationships":{},"fields":{"Category__c":{"displayValue":"Commuter","value":"Commuter"},"CreatedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Description__c":{"displayValue":null,"value":"A durable e-bike with great looks."},"Id":{"displayValue":null,"value":"a0256000001F1b7AAC"},"LastModifiedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Level__c":{"displayValue":"Beginner","value":"Beginner"},"MSRP__c":{"displayValue":"$2,700","value":2700},"Material__c":{"displayValue":"Aluminum","value":"Aluminum"},"Name":{"displayValue":null,"value":"ELECTRA X4"},"Picture_URL__c":{"displayValue":null,"value":"https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/electrax4.jpg"},"SystemModstamp":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"}},"id":"a0256000001F1b7AAC","lastModifiedById":null,"lastModifiedDate":"2018-10-09T03:29:52.000Z","recordTypeInfo":null,"systemModstamp":"2018-10-09T03:29:52.000Z"}
];
//data.meta
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>48.0</apiVersion>
    <isExposed>false</isExposed>
</LightningComponentBundle>

//------------------------------------------------------------------

//detail.html
<template>
    <template if:true={product}>
    <div class="container">
        <div class="slds-text-heading_small">{product.fields.Name.value}</div>
        <div class="price">{product.fields.MSRP__c.displayValue}</div>
        <div class="description">{product.fields.Description__c.value}</div>
        <img class="product-img" src={product.fields.Picture_URL__c.value}></img>
        <p>
            <lightning-badge label={product.fields.Material__c.value}></lightning-badge>
            <lightning-badge label={product.fields.Level__c.value}></lightning-badge>
        </p>
        <p>
            <lightning-badge label={product.fields.Category__c.value}></lightning-badge>
        </p>
    </div>
    </template>
    <template if:false={product}>
    <div class="slds-text-heading_medium">Select a bike</div>
    </template>
</template>

//detail.js
import { LightningElement, api } from 'lwc';
import { bikes } from 'c/data';


export default class Detail extends LightningElement {

    // Ensure changes are reactive when product is updated
    product;

    // Private var to track @api productId
    _productId = undefined;

    // Use set and get to process the value every time it's
    // requested while switching between products
    set productId(value) {
        this._productId = value;
        this.product = bikes.find(bike => bike.fields.Id.value === value);
    }
    
    // getter for productId
    @api get productId(){
        return this._productId;
    }
}

//detail.css
ebody{
  margin: 0;
} 
.price {
  color: green;
  font-weight: bold;
}

//detail.meta
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>48.0</apiVersion>
    <isExposed>false</isExposed>
</LightningComponentBundle>

//------------------------------------------------------------------

//list.html
<template>
    <div class="container">
        <template for:each={bikes} for:item="bike">
            <c-tile 
                key={bike.fields.Id.value} 
                product={bike} 
                ontileclick={handleTileClick}>
            </c-tile>
        </template>
    </div>
</template>

//list.js
import { LightningElement } from 'lwc';
import { bikes } from 'c/data';

export default class List extends LightningElement {
    bikes = bikes;

    handleTileClick(evt) {
        // This component wants to emit a productselected event to its parent
        const event = new CustomEvent('productselected', {
            detail: evt.detail
        });
        // Fire the event from c-list
        this.dispatchEvent(event);
    }
}

//list.css
.container {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
}

//list.meta
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>48.0</apiVersion>
    <isExposed>false</isExposed>
</LightningComponentBundle>

//------------------------------------------------------------------

//tile.html
<template>
    <div class="container">
        <a onclick={tileClick}>
            <div class="title">{product.fields.Name.value}</div>
            <img class="product-img" src={product.fields.Picture_URL__c.value}></img>
        </a>
    </div>
</template>

//tile.js
import { LightningElement, api } from 'lwc';

export default class Tile extends LightningElement {
    @api product;

    tileClick() {
        const event = new CustomEvent('tileclick', {
            // detail contains only primitives
            detail: this.product.fields.Id.value
        });
        // Fire the event from c-tile
        this.dispatchEvent(event);
    }
}

//tile.css
.container {
    border: 1px rgb(168, 166, 166) solid;
    border-radius: 5px;
    background-color: white;
    margin:5px;
    padding: 2px;
    max-width: 110px;
    display: flex;
    
}

.title {
    font-weight: strong;
}

.product-img {
    max-width: 100px;
}

a {
    text-decoration: none;
}

a:link {
    color: rgb(159, 159, 159);
}
a:visited {
    color: green;
}
a:hover {
    color: hotpink;
}
a:active {
    color: blue;
}

//tile.meta
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>48.0</apiVersion>
    <isExposed>false</isExposed>
</LightningComponentBundle>

 

 

7.쿼리문을 요청할 경우 시스템적으로 전송하기 떄문에 권한을 무시한다.

 

보안을 적용해 접근할 데이터의 여부를 결정하기 위해서는

아래의 코드처럼 작동 전 권한을 확인하고 쿼리를 실행하는 방식으로 진행할 수 있다.

// update
if (Schema.sObjectType.Contact.fields.Email.isUpdateable()) {
   // Update contact email address
}

//create
if (Schema.sObjectType.Contact.fields.Email.isCreateable()) {
   // Create new contact
}

//read
if (Schema.sObjectType.Contact.fields.Email.isAccessible()) {
   Contact c = [SELECT Email FROM Contact WHERE Id= :Id];
}

//delete
if (Schema.sObjectType.Contact.isDeletable()) {
   // Delete contact
}

 

 

8.SOQL은 SQL에서 파생된 salesforce용 SQL이기 때문에 SQL과의 차이점들이 존재한다.

  • INSERT, UPDATE, DELETE가 없으며 SELECT만 존재
  • 명령 실행 불가
  • JOIN
  • UNION 연산자
  • 쿼리 체인

 

9.SOQL Injection을 막기 위해 아래와 같은 방법들이 존재한다.

  • Static queries with bind variables - 정적 쿼리 사용을 통해 특정 위치에만 값을 변수로 할당
  • String.escapeSingleQuotes() - 작은 따음표를 없애 쿼리로 인식하지 못하게 하는 방식
  • Type casting - 형변환을 통해 예측과 다른 타입이 입력될 경우 에러를 반환하는 방법
  • Replacing characters - 공백을 제거하는 등 하나의 입력값으로 인식하게 만드는 방법
  • Allowlisting - 허용 목록을 만들어 해당 입력값이 아니면 차단하는 방식

 

10.CSRF란 특정 주소값을 통해 명령을 내리는 사이트의 경우

권한을 가진 유저를 리다이렉트를 통해 본인이 원하는 명령을 내리는 주소값으로 보내는 방식이다.

 

이를 막기 위해서 주소 접속만으로 요청을 보내지 못하게 하거나

고유한 토큰으로 정확한 값을 추측하지 못하게 하는 등의 방지법이 있다.

 

 

11.개발자 콘솔에서는 작업 공간 설정을 할 수 있는데

작업 공간은 다른 프로젝트나 다른 팀원과 겹치지 않도록 별도로 구분하는 공간이라고 볼 수 있다.

 

WorkSpace → New Workspace에서 새 작업 공간을 생성하고

WorkSpace → Switch Workspace에서 작업 공간을 이동할 수 있다.

 

 

12.디버그에서 특정 명령을 내린 경우 로그가 생성되는데

해당 로그는 Timestamp, Event, Details로 구분된다.

 

각각은 작동 시간, 이벤트 종류, 세부 사항이 출력되며

Open Raw Log를 클릭할 경우 나노초 단위까지 시간을 체크할 수 있게 된다.

 

details의 정보로는 부족하다고 생각될 경우

직접 코드 사이에 System.debug()를 사용해 조회하고 싶은 값들을 출력해볼 수 있으며

체크포인트를 사용해 해당 상태에서의 전체적인 데이터를 조회할 수도 있다.

 

일반적으로 출력되는 로그는 8가지 단계로 구분되는데

로그 출력 없음인 NONE부터 최대 많은 정보 수준인 FINEST까지 존재한다.

(NONE < ERROR < WARN < INFO < DEBUG < FINE < FINER < FINEST)

 

 

13.설계 단계에서 감지되지 않은 버그는 코딩 단계에서 10배의 시간을 소모하게 만들고

디버깅 단계에서 10배 더 많은 시간을 소모하게 만든다는 말처럼 디버깅은 쉽지 않다.

하지만 Apex Replay Debugger를 사용할 경우 체크포인트를 사용해 어디서 문제가 발생했는지 알 수 있고

SFDX: Turn On Apex Debug Log for Replay Debugger를 사용해 로그를 확인할 수 있다.

 

 

 

 

 

(1).백준 11024번 더하기 4는 다른 더하기 문제와 유사하게
입력된 숫자를 더하는 것은 같았지만 각 줄마다의 합을 출력해야 했고
최상단에 테스트케이스의 갯수가 출력됐다.

const input = `2
1 2 3 4 5
5 4 5 4 2 3 1 2`.split('\n')
const result = []
for(let i = 1 ; i < input.length ; i++){
    const arr = input[i].split(' ').map(Number)
    let sum = 0
    for(let j = 0 ; j < arr.length ; j++){
        sum += arr[j]
    }
    result.push(sum)
}

console.log(result.join('\n'))

'회고' 카테고리의 다른 글

[수습일지] - 25  (0) 2023.04.20
[수습일지] - 24  (0) 2023.04.19
[수습일지] - 22  (0) 2023.04.17
[수습일지] - 21(주말)  (0) 2023.04.16
[수습일지] - 20(주말)  (0) 2023.04.15

+ Recent posts